一、 直接插入排序
1. 执行过程:
原始序列:49,38,65,97,76,13,27
1)一开始只看49
49 38,65,97,76,13,27
2)插入38。38<49,所以49向后移动一个位置,38插入49原位置
38,49 65,97,76,13,27
3)插入65。65>49,所以直接插入在49后面
38,49,65 97,76,13,27
4)插入97。97>65,所以直接插入在65后面
38,49,65,97 76,13,27
5)插入76。76<97,所以97向后移动一个位置;继续比较,76>65,76插入到65后面
38,49,65,76,97 13,27
6)插入13。13<97,所以97向后移动一个位置;继续比较,13<76,76后移,逐个比较,13应插在最前面
13,38,49,65,76,97 27
7)插入27。27<97,所以97向后移动一个位置;继续比较。同理,发现应插在13之后
13,27,38,49,65,76,97
2. 算法思想:
每趟将一个待排序的关键字按照其值的大小插入到己经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为止。
代码:
void InsertSort(int R[],int n) { int i,j; int temp; for(i=1; i<n; ++i) { temp = R[i]; j = i - 1; } while (j>=0 && temp<R[j]) { R[j+l] = R[j]; --j; } R[j+l] = temp; }
3. 复杂度分析:
(1)时间复杂度分析由插入排序算法代码,可以选取最内层循环中的R[j+i]=R[j];这一句作为基本操作。
1)最坏的情况,即整个序列是逆序的,则内层循环中temp<R(j)这个条件是始终成立的。时间复杂度为 O(n²)。
2)最好的情况,即整个序列已经有序,则对于内层循环中temp<R[j]这个条件是始终不成立的。时间复杂度为O(n)。
综合上述两种情况,本算法的平均时间复杂度为O(n²)。
(2)空间复杂度为 O(1)。二、 折半插入排序
折半查找法的一个基本条件是序列已经有序,而从直接插入排序的流程中,每次都是在一个已经有序的序列中插入一个新的关键字,因此可以用折半查找法在这个有序序列中查找插入位置。
1. 执行过程:
现在的序列是13,38,49,65,76,97 27 49将要插入27,序列在数组中的情况为:
|--------------------已经排序-------------------------------------|-----未排序-----|
关键字 | 13 | 38 | 49 | 65 | 76 | 97 | 27 | 49 |
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1)low=0,high=5,m=|_(0+5)/2_|=2,下标为2的关键字是49,27<49,27插入49的低半区,改变high=m-1=1,low=0;
2) low=0,high=1,m=|_(0+1)/2_|=0,下标为0的关键字是13,13<27,27插入13的高半区,改变high=1,low=m+1=1;
3) low=1,high=1,m=|_(1+1)/2_|=1,下标为1的关键字是38,27<38,27插入38的低半区,改变high=m-1=0,low=1,low>high,查找结束;
4) 依次向后移动关键字97,76,65,49,38。然后插入27,一趟折半插入结束。
2. 复杂度分析:
(1)时间复杂度:最好的情况O(nlog₂n),最差情况O(n²)
(2)空间复杂度为O(1)。
三、 希尔排序
1. 执行过程:
原始序列:49,38,65,97,76,13,27,49,55,04
1)以增量为5分割序列
子序列1:49 13
子序列2: 38 27
子序列3: 65 49
子序列4: 97 55
子序列1:13 49
子序列2: 27 38
子序列3: 49 65
子序列4: 55 97
2)以增量为3分割序列对上面排序结果进行分割
子序列1:13 55 38 76
子序列2: 27 04 65
子序列3: 49 49 97
分别对3个子序列进行直接插入排序,得到:
子序列1:13 38 55 76
子序列2: 04 27 65
子序列3: 49 49 97