携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
排序算法1 --(直接插入排序)
一、算法基本思想
已知待排序列r[1...n],先将序列中的第一个记录看成是一个有序的子序列,然后从第二个记录起逐个进行插入,直至整个序列变成关键字非递减有序序列为止。 具体操作如下: (1)查找出r[i]在有序序列r[1...i-1]中的插入位置k; (2)将r[k...i-1]中所有元素全部后移一个位置; (3)将r[i]复制到r[k],则原r[1...r-1]的有序序列变成了一个r[1...i]的有序序列。 动图演示:直接插入排序动图
二、算法实现
2.1 伪代码实现
//insertion sort
1 for i ← 2 to length[A]
2 do key ← A[i]
3 //insert A[j] into the sorted sequence A[1 ... j - 1]
4 j ← i - 1
5 while j > 0 and A[j] > key
6 do A[j + 1] ← A[j]
7 j ← j - 1
8 A[j + 1] ← key
2.2 C语言代码实现
void InsertSort(ElemType A[],int n){
int i,j;
for(i = 2;i <= n;i++){ //依次将A[2]~A[n]插入到前面已排序序列
if(A[i].key < A[i-1].key){ //若A[i]的关键码小于其前驱,需将A[i]插入有序表
A[0] = A[i]; //复制为哨兵,A[0]不存放元素
for(j=i-1;A[0].key<A[j].key;--j) //从后往前查找待插入位置
A[j+1]=A[j]; //向后挪位
A[j+1]=A[0]; //复制到插入位置
}
}
}
三、复杂度分析
3.1 空间复杂度
仅使用了常数个辅助单元,因而空间复杂度为O(1)
3.2 时间复杂度
①最好情况下,表中元素已经有序,此时每插入一个元素,都只需比较一次而不用移动元素,因而时间复杂度为O(n); ②最坏情况下,表中元素顺序刚好与排序结果中元素顺序相反时,总的比较次数达到最大,为 总的移动次数也达到最大,为 ; ③平均情况下,考虑待排序表中元素是随机的,此时可以取上述最好与最坏情况的平均值作为平均情况下的时间复杂度,总的比较次数与总的移动次数均约为n²/4。由此,直接插入排序算法的时间复杂度为O(n²)
3.3 稳定性
由于每次插入元素时总是从后向前先比较再移动,所以不会出现相对位置发生变化的情况,即直接插入排序是一个稳定的排序方法。
3.4 适用性
直接插入排序适用于顺序存储和链式存储的线性表。为链式存储时,可以从前往后查找指定元素的位置。 大部分排序算法都仅适用于顺序存储的线性表。
排序算法2--(折半插入排序)
一、算法基本思想
二分插入法与直接排序类似,只是在确定插入位置的方法是用二分法,即从第0个数据开始依次折半与待插入的数据进行比较直到找到合适的位置。
二、算法实现
2.1 伪代码实现
暂无
2.2 C语言代码实现
//折半插入排序
void BInsertSort(int a[], int n)
{
int i,j,low,high;
for(int i =2;i<=n;i++){
A[0]=A[1];
low=1;
high = i-1;
while(low<=high){ //折半查找
mid = (low+high)/2;
if (a[mid]>temp) high=mid-1;
else low=mid+1;
}
for(int j=i;j>low;j--) //统一后移元素,空出插入位置
a[j] = a[j-1];
a[low] =temp;
}
}
三、复杂度分析
3.1 空间复杂度
仅使用了常数个辅助单元,因而空间复杂度为O(1)
3.2 时间复杂度
折半插入排序仅减少了比较元素的次数,约为O(nlog2^n),该比较次数与待排序初始状态无关,仅取决于表中的元素个数n;而元素的移动次数未改变,它依赖于待排序表的初始状态。因此复杂度依然为O(n2)。
3.3 稳定性
稳定
3.4 适用性
适用于数据量不大的排序表