由于大学学的是C++,所以这里全部用C++来实现
今天准备写的内容为以下八块:
- 1. 直接插入排序(Straight Insertion Sort)
- 2. 希尔排序(Shells Sort)
- 3. 直接选择排序(Straight Selection Sort)
- 4. 堆排序(Heap Sort)
- 5. 冒泡排序(Bubble Sort)
- 6. 快速排序(Quick Sort)
- 7. 归并排序(Merge Sort)
- 8. 桶排序(Bucket Sort)/基数排序(Radix Sort)
- 9. 各种排序算法性能比较
排序有内部排序和外部排序之分,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。我们这里说的八大排序算法均为内部排序。
下图为排序算法体系结构图:
常见的分类算法还可以根据排序方式分为两大类:比较排序和非比较排序。本文中前七种算法都是比较排序,非比较排序有三种,分别为:
1)计数排序(Count Sort)(复杂度O(n+k)(其中k是待排序的n个数字中最大值),参见《计数排序-Counting Sort》)
2)基数排序(Bucket Sort)(复杂度O(nk)(其中k是最大数字的位数),参见《最快最简单的排序—桶排序》)
3)桶排序(Radix Sort)(复杂度O(n+k)(其中k是待排序的n个数字中最大值),参见《基数排序(Radix Sorting)》)
非比较排序的特点是时间复杂度很低,都是线性复杂度O(n),但是非比较排序受到的限制比较多,不是通用的排序算法。本文主要讲解七种比较排序算法,最后单独介绍一下非比较排序算法。
1. 直接插入排序(Straight Insertion Sort)
基本思想:将待排序的无序数列看成是一个仅含有一个元素的有序数列和一个无序数列,将无序数列中的元素逐次插入到有序数列中,从而获得最终的有序数列。
算法流程:
1)初始时, a[0]自成一个有序区, 无序区为a[1, ... , n-1], 令i=1;
2)将a[i]并入当前的有序区a[0, ... , i-1];
3)i++并重复2)直到i=n-1, 排序完成。
时间复杂度:O(n^2)。
示意图:初始无序数列为 49, 38, 65, 97, 76, 13, 27 ,49
说明:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
C++实现源码:
//直接插入排序,版本1 void StraightInsertionSort1(int a[], int n) { int i, j, k; for(i=1; i<n; i++) { //找到要插入的位置 for(j=0; j<i; j++) if(a[i] < a[j]) break; //插入,并后移剩余元素 if(j != i) { int temp = a[i]; for(int k=i-1; k>=j; k--) a[k+1] = a[k]; a[j] = temp; } } PrintDataArray(a, n); }
两种简化版本,推荐第三版本。
//直接插入法,版本2:搜索和后移同时进行 void StraightInsertionSort2(int a[], int n) { int i, j, k; for(i=1; i<n; i++) if(a[i] < a[i-1]) { int temp = a[i]; for(j=i-1; j>=0 && a[j]>temp; j--) a[j+1] = a[j]; a[j+1] = temp; } PrintDataArray(a, n); } //插入排序,版本3:用数据交换代替版本2的数据后移(比较对象只考虑两个元素) void StraightInsertionSort3(int a[], int n) { for(int i=1; i<n; i++) for(int j=i-1; j>=0 && a[j]>a[j+1]; j--) Swap(a[j], a[j+1]); PrintDataArray(a, n); }
2. 希尔排序(Shells Sort)
希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。希尔排序又叫缩小增量排序
基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
算法流程:
1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2)按增量序列个数k,对序列进行k 趟排序;
3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
时间复杂度:O(n^(1+e))(其中0<e<1),在元素基本有序的情况下,效率很高。希尔排序是一种不稳定的排序算法。
希尔排序的示例: