所谓排序,就是对数据元素集合建立某种有序排序的过程。也就是对它的关键字进行排序。
所谓稳定性,就是关键字相同的两个数据元素在排序结束后不会改变两者之间的相对位置。一般不稳定算法效率较高。
内部排序和外排序:内排序就是说数据元素能够全部放入内存中排序,而外排序是指因为数据元素太多了,数据元素不能全部放入内存中,需要不断的在内存和外存之间交换数据元素的排序。
按照时间复杂度可将排序分为三种:简单的排序方法,时间复杂度为O(n^2);快速的排序方法,时间复杂度为O(nlogn);基数排序方法,时间复杂度为O(d*n)。
交换排序
排序表中数据元素按关键字两两比较,发生逆序,则交换位置。
冒泡排序:每一次排序都将最大值以后排序表后面。
快速排序:又叫分区交换排序,取一基数,将排序表分为左右两个子表,基数大于等于左侧子表,小于右侧子表。
插入排序
每次将数据元素插入到有序的部分子表中。
直接插入排序:把第一个数据元素当作有序表,将后面的元素依次简单地插入进来。
折半插入排序:插入的时候通过折半查找的方法找到插入点
希尔排序:又称缩小增量排序,取一个间隔d<n,将排序表分为d个子表,每个子表使用直接插入排序,然后缩小间隔d,重复直到d=1,再排序。
选择排序
每一趟,选择一个最小的元素,下一趟选择次小的元素,最后就排好了。
直接选择排序:每一趟选择一个最大值,存入表的前端。
锦标赛排序:使用了完全二叉树,n个数据元素,两两分组,比较,得出优胜者(关键字最小),做个两个数据元素的父节点,然后继续比较、得出优胜者,直到得到根节点,根节点为优胜者。将优胜者从叶节中用无穷大替代,重新得出优胜者。重复下去,每次抛出的值构成有序的表。因为每一趟都利用到了前一趟比较的结果,因此比直接选择排序效率要高。
堆排序:在数组上构建最大堆,将堆顶元素(关键字最大)抛出,放入数组后面,重新调整堆,重复。关于堆的操作:二叉树应用-堆
归并排序
所谓归并,就是讲两个或两个以上的有序表合并成一个新的有序表。
两路归并排序:将含有n个数据元素的表看成长度为1的n个有序子表,两两归并,得到长度为2的ceil(n/2)个有序表,反复,直到得到长度为n的有序表。
基数排序
通过使用对多关键字进行排序的“分配”和“收集”的方法,基数排序实现了对单关键字排序。就是说,基数排序是多关键字的一种,具体使用了最低位优先法LSD。多关键字排序就是关键字不止一个,分别对每个关键字排序。
基数排序:关键字为单个,但是按照位数,将关键字拆成多位,每一位都进行分配和回收操作。分配按照不同的基数值(radix)放入不同的桶中,分配的过程就是排序的过程。
各种方法选择
考虑因素:大小、分布情况、稳定性。
- 若排序表长度较小,可采用简单的排序方法,比如直接插入排序、直接选择排序、冒泡排序。直接插入排序和冒泡排序的元素移动次数较多。
- 排序表长度较大时,可采用快速的排序方法,时间复杂度为O(nlog2n)。比如快速排序、希尔排序、堆排序和归并排序。当关键值分布随机时,快速排序平均运行时间最小;堆排序只需一个记录的辅助空间(O(1)),且不会像快速排序那样,出现最坏的情况;希尔排序是一种插入排序,故移动的次数多,当记录接近有序时,排序较快。上面三种排序方法都不是稳定的,而归并排序是稳定的。排序过程中可将多种排序方法联合使用,比如将归并排序和直接插入排序联合,先直接插入排序得到长度较小的有序表,然后归并,当子表较大时,但是已经接近有序了,因此直接插入仍旧很快。
- 若待排序表基本有序,可使用直接插入排序或冒泡排序。
- 当n很大而关键字位数较小时,可考虑采用基数排序方法。
参考:
《数据结构---c++实现》缪淮扣