1. 直接插入排序
直接插入排序:指每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
具体方法:
第一趟比较前两个数,然后把第二个数按大小插入到有序表中;
第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;
依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
我们看一下排序简要过程:
原序列:5 1 2 4 3
用一个小例子列举一下排序过程:(含代码步骤)
上述过程的代码片:
代码的核心是比较和后移,注意要将待定元素多存一份,因为后移时,会占据该元素的位置。
void DirectInsertionSort(int* a, int n)// 直接插入排序
{
for (int i = 0; i < n - 1; ++i)
{
int end = i;// 下标
int index = a[end + 1];// 记录待定的值
while (end >= 0)
{
if (index < a[end])
{
a[end + 1] = a[end]; // 移动元素
--end;
}
else break;
}
a[end + 1] = index;// 插入待定值
}
}
总结
稳定性:稳定
时间复杂度:O(N2)
空间复杂度:O(1)
最好:顺序O(N) 最坏:逆序O(N2)
元素序列越接近有序,直接插入排序算法的时间效率越高。
2. 希尔排序
希尔排序: 对直接插入排序算法的优化。
把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
具体方法:
首先确定一个正整数d1,使得d1<n,所有序号相隔d1的元素为一组,组内进行直接插入排序;
然后取d2<d1,重复上述分组和排序操作;
直至di=1,即所有记录放进一个组中排序为止。
我们看一下排序简要过程:
最常用的初始步长就是length/2。在这个例子中,length=9,所以初始步长gap=4。
1. 我们将原序列分成四组 (步长是多少就分多少组!):
2. 分好组之后,每个组内进行直接插入排序:
3. 改变步长,新步长是旧步长的二分之一,gap=gap/2=2,重新分为2组:
4. 重新分好组之后,每个组内进行直接插入排序:
5. 重新改变步长,新步长是旧步长的二分之一,gap=gap/2=1,重新分为1组:
6. 重新分好组之后,组内进行直接插入排序:
7. 步长gap=gap/2=0,此时排序完成。
代码实现:
void ShellSort(int* a, int n)// 希尔排序
{
int gap = n;
while (gap > 1)
{
//gap = gap / 2; // 一般情况下,gap是一半一半
gap = gap / 3 + 1;// 这种情况更好一点
for (int i = 0; i < n - gap; ++i)// 循环每个组都要进行直接插入排序
{
int end = i;
int index = a[end + gap];
while (end >= 0)
{
if (index < a[end])
{
a[end + gap] = a[end];
end = end - gap;
}
else break;
}
a[end + gap] = index;
}
}
}
总结
稳定性:不稳定
平均时间复杂度:O(nlogn)—O(N2)
空间复杂度:O(1)
上述代码中gap=gap/2 ,最坏:O(N2)
还有 gap=gap/3+1 ,最好:O(N1.3- N2) 最坏:O(N2)
在此推荐一个博客:https://blog.csdn.net/qq_39207948/article/details/80006224