标签:
插入排序是一种简单直观的排序方法,其基本思想在于每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中,直到全部记录插入完成。
1. 直接插入排序
基本思想:
直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。
1 #include <iostream> 2 using namespace std; 3 4 void insertSort(int A[], int n) 5 { 6 int i, j; 7 for (i = 2; i <= n; i++) // 依次将A[2]~A[n]插入到前面已排序序列 8 { 9 if (A[i] < A[i-1]) // 若A[i]的关键码小于其前驱,需将A[i]插入有序表 10 { 11 A[0] = A[i]; // 复制为哨兵 12 for (j = i-1; A[0] < A[j]; j--) // 从后往前查找待插入位置 13 A[j+1] = A[j]; // 向后挪位 14 A[j+1] = A[0]; // 复制到插入位置 15 } 16 } 17 } 18 19 int main(int argc, char *argv[]) 20 { 21 int arr[] = {-1, 99, 88, 33, 66, 77, 44, 102, 35, 47, 25}; 22 insertSort(arr, 10); 23 for (int i = 1; i <= 10; i++) cout << arr[i] << " "; 24 cout << endl; 25 26 return 0; 27 }
效率分析:
直接插入排序的时间复杂度O(n2),空间复杂度O(1);
在最好的情况下,表中元素已经有序,此时每插入一个元素,都只需要比较一次而不用移动元素,因而时间复杂度为O(n)。
稳定性:每插入一个元素时总是从后向前先比较再移动,所以不会出现相同元素相对位置发生变化的情况,即直接插入排序是一个稳定的排序方法。
2. 希尔排序
基本思想:
希尔排序的基本思想是:先将待排序表分割成若干形如L[i, i+d, i+2d, ..., i+kd]的“特殊”子表,分别进行直接插入排序,当整个表中元素已呈“基本有序”时,再对全体记录进行一次直接插入排序。希尔排序的排序过程如下:
先取一个小于n的步长d1,把表中全部记录分成d1组,所有距离为d1的倍数的记录放在同一个组中,在各组中进行直接插入排序;
然后取第二个步长d2,重复上述过程,直到所取到的dt=1,即所有记录已放在同一组中,再进行直接插入排序,由于此时已经具有较好的局部有序性,故可以很快得到结果。
到目前为止,尚未求得一个最好的增量序列,希尔提出的方法是d1=n/2,di+1=[di/2],并且最后一个增量是1。
一趟增量为dk的希尔插入过程如下:
1 void shellInsert(int A[], int n, int dk) 2 { 3 int i, j; 4 for (i = dk+1; i <= n; i++) 5 { 6 if (A[i] < A[i-dk]) // 需要将A[i]插入有序增量子表 7 { 8 A[0] = A[i]; // 暂存在A[0] 9 for (j = i-dk; j > 0 && A[0] < A[j]; j -= dk) 10 A[j+dk] = A[j]; // 记录后移,查找插入位置 11 A[j+dk] = A[0]; // 插入 12 } 13 } 14 }
通过多次调用一趟希尔插入过程,我们可以将表最终排列为有序。希尔排序算法如下:
1 void shellSort(int A[], int n, int dlta[], int t) 2 { // 按增量序列dlta[0..t-1]对A作希尔排序 3 int k; 4 for (k = 0; k < t; k++) 5 shellInsert(A, n, dlta[k]); 6 }
效率分析:
空间复杂度:O(1)。
时间复杂度:由于希尔排序的时间复杂度依赖于增量序列的函数,这涉及数学上尚未解决的难题,所以其时间复杂度分析比较困难。当n在某个特定范围时,希尔排序的时间复杂度约为O(n1.3)。在最坏情况下希尔排序的时间复杂度为O(n2)。
稳定性:当相同的关键字的记录被划分到不同的子表时,可能会改变它们的相对次序,因此,希尔排序是一个不稳定的排序方法。例如,表L={3, 2, 2},经过一趟排序后,L={2, 2, 3},最终排序序列也是{2, 2, 3},显然,2与2的相对次序已经发生了变化。
标签:
原文地址:http://www.cnblogs.com/xiaoxxmu/p/5448222.html