mirror of
https://github.com/hao14293/2021-Postgraduate-408.git
synced 2026-07-09 04:26:10 +08:00
排序
插入排序
基本思想:每一趟讲一个待排序的记录,按其关键字的大小插入到已排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。
直接插入排序(straight Insertion sort)
核心:通过构建有序序列,对于未排序序列,在已排序序列中从后向前扫描(对于单向链表则只能从前往后遍历),找到相应位置并插入。
- 从第一个元素开始,该元素可认为已排序
- 取下一个元素,对已排序数组从后往前扫描
- 若从排序数组中取出的元素大于新元素,则移至下一位置
- 重复步骤3,直至找到已排序元素小于或等于新元素的位置
- 插入新元素至该位置
- 重复2~5
代码实现
#include <iostream>
using namespace std;
int main(){
int a[] = {-1, 6, 5, 2, 8, 4, 1, 3, 7}; //数组从第二位开始,第一位[0]为暂存单元
int len = sizeof(a) / sizeof(a[0]);
for(int i = 2; i < len; i++){
if(a[i] < a[i - 1]){
a[0] = a[i];
a[i] = a[i - 1];
int j = i - 2;
while(a[0] < a[j]){
a[j + 1] = a[j];
j--;
}
a[j + 1 ] = a[0];
}
}
for(int i = 1; i < len; i++)
cout << a[i];
return 0;
}
算法分析
- 空间复杂度:需要一个记录的辅助空间[0],空间复杂度为 O(1).
- 时间复杂度:一共操作了 n-1 趟,每趟都分为比较和移动两部分。最好情况,只比较不移动,O(n);最坏情况,比较 n^2/2 次,移动 n^2/2 次, 时间复杂度为O(n^2).
算法特点
- 稳定排序。
- 也适合于链式存储,只需修改相应的指针,无需移动。
- 适合于初始记录基本有序(正序)的情况,当初始记录无序,n较大时,此算法时间复杂度较高,不宜使用。
折半插入排序(Binary Insertion Sort)
直接插入排序每一趟都需要在排好序的部分中从最后一位开始比较。折半插入排序减少了比较的次数,但移动次数没有改变。
代码实现
#include <iostream>
using namespace std;
int main(){
int a[] = {-1, 6, 5, 2, 8, 4, 1, 3, 7}; //数组从第二位开始, 第一位[0]为暂存单元
int len = sizeof(a) / sizeof(a[0]);
for(int i = 2; i < len; i++){
a[0] = a[i];
int low = 1, high = i - 1;
while(low <= high){
int m = (low + high) / 2;
if(a[0] < a[m]) high = m - 1;
else low = m + 1;
}
for(int j = i - 1; j >= high + 1; j--)
a[j + 1] = a[j];
a[high + 1] = a[0];
}
for(int i = 1; i < len; i++)
cout << a[i];
return 0;
}
算法分析
- 时间复杂度:移动次数没有变,所以时间复杂度还是 O(n^2).
- 空间复杂度:O(1).
算法特点
- 稳定排序。
- 只能用于顺序结构,不能用于链式结构。
- 适合初始记录无序、n较大时的情况。
