第八章 排序
8.1 基本概念和排序方法概述
8.1.1 排序的基本概念
1. 排序
排序是按照关键字的非递减或非递增顺序对一组记录重新进行排序的操作;
2. 排序的稳定性
稳定排序:能够使任何数据相等的元素,排序以后相对次序不变;
非稳定性排序:不是稳定排序的方法;
3. 内部排序和外部排序
内部排序:指的是待排序记录全部存放在计算机内存中进行排序的过程;
外部排序:指的是待排序记录的数量很大,以至内存一次不能容纳全部记录;
8.1.2 内部排序方法的分类
1.插入类;2.交换类;3.选择类;4.归并类;5.分配类;
8.1.3 待排序记录的存储方式
顺序表,链表和待排序记录;
8.1.4 排序算法效率的评价指标
1.操作时间 2.辅助空间
8.2 插入排序
基本思想:每一趟将一个待排序的记录,按其关键字的大小插入已经排好序的一组记录的适当位置,直到所有待排序记录全部插入为止;
8.2.1 直接插入排序
直接插入排序:一种最简单的排序方法,其基本操作使一条记录插入已排好序的表,从而得到一条新的,记录数量增1的有序表;
将待插入的数据使用顺序查找法进行比较直到当表中数据小于待插入数据时,插入表中数据的前一位;
添加哨兵:将待插入的数据放到位序为0的位置,然后用哨兵按顺序查找法与每一个元素进行比较,直到小于哨兵的元素后,将哨兵插入该元素位序加一;
时间复杂度:O(n^2)
空间复杂度:O(1)
算法特点:
- 稳定排序
- 算法简便
- 也适用于链式存储结构,只是在单链表上无需移动记录,只需修改相应的指针;
- 更适合于初始记录基本有序的情况,当初始记录无序,n较大时,空间复杂度较高,不宜采用;
8.2.2 折半插入排序
类似于折半查找法,利用双指针来对待插入记录和中间位置的记录进行比较,直到将记录插入high+1位序;
时间复杂度:O(n^2);折半插入排序仅减少了关键空间的比较次数,而记录的移动次数不变;平均性能优于直接插入排序;
空间复杂度:O(1);
算法特点:
- 稳定排序
- 只适用于顺序结构,不能用于链式结构;
- 适合初始记录无序,n较大的情况;
8.2.3 希尔排序
将固定间隔的记录进行排序;
希尔排序从“减少记录个数(缩小增量)”和“序列基本有序”两个方面对直接插入排序进行改进;
特点:
- 一次移动,移动位置较大,跳跃式地姐姐排序后的最终位置;
- 最后一次只需要少量移动;
- 增量序列必须是递减的,最后一个必须是1;
- 增量序列应该是互质的;
8.3 交换排序
基本思想:两两比较待排序记录的关键字,一旦发现两个记录不满足次序要求时则进行交换,直到整个序列全部满足要求为止;
8.3.1 冒泡排序
冒泡排序:一种最简单的交换排序法,通过两两比较相邻记录来进行交换从而得到满足要求的序列;
- 将待排序的记录存放在数组里面,将数组内的记录两两进行比较,直到最大的记录在最右边n的位置;
- 第二轮冒泡排序,从第一个记录开始与相邻的记录两两进行比较,直到最大的记录在n-1的位置;
- 重复以上操作直到某一趟排序中没有要交换的记录,则排序成功;
算法特点:
- 稳定排序;
- 可用于链式存储结构;
- 移动记录次数较多,算法的平均时间性能比直接插入排序差;
时间复杂度:O(n^2);
空间复杂度:O(1);
8.3.2 快速排序
快速排序是由冒泡排序改进而得;
基本思想:
- 任取一个记录(通常取第一个记录)作为枢轴(支点),设其关键字为pivotkey;
- 所有关键字小于pivotkey的记录交换到前面,大于pivotkey的交换到后面;
- 对各子表重新选择中心元素并一次规则调整;
- 直至每个子表只有一个记录;
(利用一个记录将小于这个记录的所有记录放在前面,大于其的放在后面,重复该操作直到排序成功;)
(用两个指针,首先将枢轴设为pivotkey移除数组,然后与两个指针所指向的记录与pivotkey进行比较然后看是否交换,直到两个指针重合后将pivotkey移入重合位置,重复该操作;)
算法特点: - 记录非顺次的移动导致排序方法是不稳定的;
- 排序过程中需要定位表的上界和下界,所以适合顺序结构,很难用于链式结构;
- 当n较大时,在平均情况下快速排序是所以内部排序方法中速度最快的一种,所以其适合初始记录无序,n较大的情况;
时间复杂度:O(nlog2 n);
空间复杂度:O(n);
8.4 选择排序
基本思想:每一趟从待排序的记录中选出关键字最小的记录,按顺序将其放在已排好序的记录序列最后,直到全部排完为止;
8.4.1 简单选择排序
也称直接选择排序
将待排序的记录放在数组内,选择第一个记录经过n-1次比较从n个记录中选出最小的记录与第一个记录进行交换,下一趟从第二个记录开始,以此类推直到排序完成;
时间复杂度:O(n^2);
空间复杂度O(1);
算法特点:
- 是一个稳定的排序方法;
- 可用于链式存储结构;
- 移动记录次数较少,当每一个记录占用的空间较多时,此方法比直接插入排序快;
8.4.2 树型选择排序
树型选择排序又称锦标赛排序,是一种按找锦标赛的思想进行选择排序的方法;
(通过二叉树的形式将记录进行两两比较,较小者放在根结点)
8.4.3 堆排序
堆分为小根堆和大根堆,小根堆的跟顶元素必定为n个记录中的最小值,大根堆同理;
1.调整堆
在大根堆(或小根堆)与最后一个叶子结点进行交换后再次调整为大根堆(或小根堆)的操作;
2.建初堆
将一个无序序列调整为堆,就必须将其所对应的完全二叉树以每一结点为根的子树都要调整为堆;
3.堆排序算法的实现
堆排序是一种树形结构,在排序过程中,将待排序的记录看成一棵完全二叉树的顺序存储结构,利用完全二叉树中的双亲结点和孩子结点之间的内在关系,在当前无序的列表中选择关键字最大(或最小)的记录;
- 将待排序的记录放入完全二叉树内,然后孩子结点中最小或最大的记录放在双亲结点直到根结点为待排序记录的最大值或最小值,直到构成一个小根堆或大根堆;
- 将根结点与最后的叶子节点进行交换,使最大的数(或最小的数放在最后一端),然后进行调整称为大根堆(或小根堆);
- 重复以上操作,直至使堆成为一个有序序列;
时间复杂度:O(nlog2 n);
空间复杂度:O(1);
8.5 归并排序
归并排序就是将两个或两个以上的有序表合并成一个有序表的过程;
算法思想:将初始含有n个记录的序列看作n个长度为1的有序的子序列,然后两两归并,得到n/2个长度为1或2的有序子序列;再两两归并,重复该操作,直到得到一个长度为n的有序序列为止;
2-路归并:将两个有序表归并成一个有序表的过程;
2-路归并排序中的核心操作:将待排序序列中前后相邻的两个有序序列归并为一个有序序列;
时间复杂度:O(nlog2 n);
空间复杂度:O(n);
8.6 基数排序
从最低位(个位)开始进行,按关键字的不同收集,然后按第二低位(十位)开始进行,按关键字的不同收集,若有些数没有更低位,则按0收集
算法特点:
- 是稳定排序;
- 可用于链式结构,也可用于顺序结构
- 时间复杂度可以突破基于关键字比较一类方法的下界O(nlog2 n),达到O(n)
- 基数排序使用条件有严格要求:需要直到各级关键字的主次关系和各级关键字的取值范围;
时间复杂度:O(d(n+rd));
空间复杂度:O(n+rd);//d个关键字