数据结构-排序(二)插入排序
一、 直接插入排序
1、算法思想
算法思想: 每次将⼀个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插⼊完成。
排序过程:
- 整个排序过程为n-1趟插入,
- 先将序列中第1个记录看成是一个有序子序列,
- 然后从第2个记录开始,逐个进行插入,直至整个序列有序。
以上gif动图制作,图像来自网站:VisuAlgo
链表实现请参考:链表实现直接插入排序
2、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <iostream> #include <string> using namespace std;
bool InsertSort(int arr[], int n) { for (int i = 1; i < n; i++) { if (arr[i] < arr[i - 1]) { int t = arr[i]; int j; for (j = i - 1; j >= 0 && arr[j] > t ; j--) { arr[j + 1] = arr[j]; } arr[j + 1] = t; } } }
void PrintArray(int arr[], int n) { for (int i = 0; i < n; i++) { cout << arr[i] << " "; } printf("\n"); } int main() { int arr[] = {12, 28, 20, 50, 48, 1, 5, 28}; int n = sizeof(arr) / sizeof(arr[0]); cout << "输出初始数组" << endl; PrintArray(arr, n); cout << "直接插入排序" << endl; InsertSort(arr, n); cout << "输出排序后数组" << endl; PrintArray(arr, n); return 0; }
|
1 2 3 4 5
| 输出初始数组 12 28 20 50 48 1 5 28 直接插入排序 输出排序后数组 1 5 12 20 28 28 48 50
|
3、算法效率分析
1、空间复杂度: O(1)
2、时间复杂度: 主要来自对比关键字、移动元素若有 n 个元素,则需要 n-1 趟处理
最好情况:共n-1趟处理,每⼀趟只需要对比关键字1次,不⽤移动元素
最好时间复杂度—— O(n)
最坏情况:
第1趟:对比关键字2次,移动元素3次
第2趟:对比关键字3次,移动元素4次
…
第 i 趟:对比关键字 i+1次,移动元素 i+2 次
最坏时间复杂度——$O(n^2)$
最好时间复杂度(全部有序):O(n)
最坏时间复杂度(全部逆序):$O(n^2)$
平均时间复杂度:$O(n^2)$
3、算法稳定性: 稳定
二、折半插入排序
1、算法思想
算法思想: 先用折半查找找到应该插⼊的位置,再移动元素
- 当 low > high 时折半查找停止,应将 [low, i-1] 内的元素全部右移,并将 A[0] 复制到 low 所指位置
- 当 A[mid] == A[0] 时,为了保证算法的“稳定性”,应继续在 mid 所指位置右边寻找插入位置
2、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
bool SplitInsertSort(int arr[], int n ) { for (int i = 2; i <= n ; i++) { arr[0] = arr[i]; int low = 1, high = i - 1; while (low <= high) { int mid = (low + high) / 2; if (arr[mid] > arr[0]) { high = mid - 1; }else { low = mid + 1; } } for (int j = i - 1; j >= high + 1 ; --j) { arr[j + 1] = arr[j]; } arr[high + 1] = arr[0]; } }
|
3、算法效率分析
1、空间复杂度: O(1)
2、时间复杂度:
比起“直接插⼊排序”,比较关键字的次数减少了,但是移动元素的次数没变,整体来看时间复杂度依然是$O(n^2)$
3、算法稳定性: 稳定