第七章 排序

第七章 排序

1 排序的基本知识

1.1 排序的意义

排序就是将原本无序的序列重新排列成有序的序列

1.2 排序的稳定性

如果待排序表中有两个元素Ri、Rj,其对应的关键字keyi=keyj,且在排序前Ri在Rj前面,如果使用某一排序算法排序后,Ri仍然在Rj的前面,则称这个排序算法是稳定的,否则称排序算法是不稳定的。

1.3 直接插入排序

首先以一个元素为有序的序列,然后将后面的元素依次插入到有序的序列中合适的位置直到所有元素都插入有序序列。

空间复杂度:在下标为0处存储哨兵,是常数个辅助空间大小,所以空间复杂度为O(1)

时间复杂度:最坏情况下,整个序列都是逆序;最好情况下,整个序列都是顺序

2 插入类排序

2.1 插入类排序的定义

插入类排序就是在一个有序的序列中,插入一个新的关键字,直到所有的关键字都插入形成一个有序的序列

2.2 折半插入排序

将比较和移动这两个操作分离出来,也就是先利用折半查找找到插入的位置,然后一次性移动元素,再插入该元素。

时间复杂度O(nlog2n)

时间复杂度还是O(n2)

2.3 希尔排序(缩小增量排序)

基本思想:希尔排序本质上还是插入排序,只不过是把待排序序列分成几个子序列(按照一定增量(一组元素中下标的差值)),再分别对这几个子序列进行直接插入排序

希尔排序的优势:希尔排序的每一轮都会使整个序列变得越来越有序,最后一轮当增量为1的时候,整个序列几乎都是有序的,所以进行直接插入排序会提高排序的效率。

时间复杂度:希尔排序的时间复杂度约为O(n1.3),在最坏情况下希尔排序的时间复杂度为O(n2)

空间复杂度:希尔排序的空间复杂度为O(1)

3 交换类排序

3.1 交换类排序的定义

根据序列中两个元素关键字比较结果来交换它们在序列中的位置

3.2 冒泡排序

假设待排序表长为n,从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即A[i-1]>A[i]),则交换它们,直到序列比较完。我们称它为一趟冒泡,结果将最小的元素交换到待排序列的第一个位置。下一趟冒泡时,前一趟确定的最小元素不再参与比较,待排序列减少一个元素,每趟冒泡的结果把序列中的最小元素放到了序列的最终位置,……,这样最多做n-1趟冒泡就能把所有元素排好序。

空间复杂度

交换时开辟了存储空间来存储中间变量,所以空间复杂度为O(1)

时间复杂度

最坏情况下,初始序列就是逆序的,那么对于外层每一次循环,内层循环始终成立,外层循环i从0执行到n-1,第i次内层循环执行次数为n-1-i,所以一共执行 i = 0 n 1 n 1 i \sum_{i = 0}^{n - 1}n - 1 - \mathbb{i} =n(n-1)/2 所以最坏情况下时间复杂度为O(n2)。

最好情况下,初始序列就是顺序的,内层循环if条件始终不成立,所以内层执行n-1次后结束,所以时间复杂度为O(n)

3.3 快速排序

快速排序是一种基于分治法的排序方法。

每一趟快排选择序列中任一个元素作为枢轴(pivot)(通常选第一个元素),将序列中比枢轴小的元素都移到枢轴前边,比枢轴大的元素都移到枢轴后边。

时间复杂度

最好情况下时间复杂度为O(nlogn) ,待排序序列越无序,算法效率越高。

最坏情况下时间复杂度为O(n2),待排序序列越有序,算法效率越低。

空间复杂度

由于快速排序是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应与递归调用的最大深度一致。

最好情况下为 ⌈log2(n+1)⌉(每次partition都很均匀)递归树的深度O(logn)

最坏情况下,因为要进行n-1次递归调用,所以栈的深度为O(n);

4 选择类排序

4.1 选择类排序的定义

每一趟在后面n-i+1(i=1,2,3,······,n-1)个待排序元素中选取关键字最小的元素,直到第n-1趟做完,待排序元素只剩下1个,就不用再选了。

简单选择排序

依次从后面序列中选择当前最小的元素作为第i个元素,如果这个值更小,则更新min值为这个更小的元素所在下标;如果第i个元素不是剩下元素最小的,则和最小的进行交换;最后一个元素不需要排序。

空间复杂度是O(1)

时间复杂度为O(n2)

4.2 堆排序

堆是一棵完全二叉树,而且满足任何一个非叶结点的值都不大于(或不小于)其左右孩子结点的值。

如果是每个结点的值都不小于它的左右孩子结点的值,则称为大顶堆。

如果是每个结点的值都不大于它的左右孩子结点的值,则称为小顶堆。

堆排序的思想

每次将无序序列调节成一个堆,然后从堆中选择堆顶元素的值,这个值加入有序序列,无序序列减少一个,再反复调节无序序列,直到所有关键字都加入到有序序列。

调整方法:二叉树由下至上由右至左(数组的下标由大到小),检查每个结点是否满足大顶堆的要求,如果不满足进行调整。

二叉树性质5:

对完全二叉树按从上到下、从左到右的顺序依次编号1,2,…,N,则有以下关系:

  1. 当i>1时,结点i的双亲结点编号为⌊i/2⌋,即当i为偶数时,其双亲结点的编号为i/2,它是双亲结点的左孩子;当i为奇数时,其双亲结点的编号为(i-1)/2,它是双亲结点的右孩子。

  2. 当2i≤N时,结点i的左孩子编号为2i,否则无左孩子。

  3. 当2i+1≤N时,结点i的右孩子编号为2i+1,否则无右孩子。

空间复杂度

堆排序只需要在交换结点的时候需要额外存储空间来辅佐,所以空间复杂度为O(1)

时间复杂度

堆排序的总时间可以分为①建堆部分的时间复杂度O(n)+②n-1次向下调整堆的时间复杂度为O(nlog2n)=O(nlog2n)

5 归并排序

假定待排序表含有n个记录,则可以看成是n个有序的子表,每个子表长度为1,然后两两归并,得到
⌈n/2⌉个长度为2或1的有序表;再两两归并,……如此重复,直到合并成一个长度为n的有序表为止,这种排序方法称为2-路归并排序。

时间复杂度:O(nlog2n)

空间复杂度:O(n)

6 基数排序

基数排序(也叫桶排序)是一种很特别的排序方法,它不是基于比较进行排序的,而是采用多关键字排序思想(即基于关键字各位的大小进行排序的),借助“分配”和“收集”两种操作对单逻辑关键字进行排序。基数排序又分为最高位优先(MSD)排序和最低位优先(LSD)排序。

桶实际是一个队列,先进先出(从桶的上面进,下面出)

空间复杂度:O®

时间复杂度:O(d(n+r))

7 外部排序

需要将待排序的记录存储在外存上,**排序时再把数据一部分一部分的调入内存进行排序。**在排序过程中需要多次进行内存和外存之间的交换,对外存文件中的记录进行排序后的结果仍然被放到原有文件中。这种排序的方法就叫做外部排序。

7.1 置换-选择排序

可以对无序的序列得到初始的归并段。

7.2 最佳归并树

如果把各个归并段的长度记做是某个结点的权值,那么最佳归并树就是一棵N路的哈夫曼树

最佳的归并策略可以通过最佳归并树来找到,但是对于多路归并来说,每次归并如何得到最值的关键字

7.3 败者树

败者树可以看成是一棵完全二叉树:

这棵树的叶子结点存储的各个归并段当前参加比较的记录,内部结点存储的则是左右子树当中的失败者。

胜利者则一直继续向上比较直到根结点。

由于每次归并我们都是希望找到各个归并段中最小的关键字,所以胜利者应该是左右子树中关键字较小的。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/williananjhon/article/details/92560849