排序算法大致可分为:
1.插入排序 --- 直接插入排序、希尔排序
2.选择排序 --- 选择排序、堆排序
3.交换排序 --- 冒泡排序、快速排序
4.归并排序
本篇博客主要介绍插入排序。。
ps:以下两种排序算法都是以升序为例讲解!
一、直接插入排序
直接插入排序的思想:
假设数组第一个数是有序的,从第二个数开始遍历,每拿出一个数就和前面的有序的数比较,如果比它小,就往前面插;否则就排在后边,插入后将前面的有序数组+1。这样走下去,前面的一部分数组总是有序的,直到遍历完这个数组后,整个数组也是有序的。(其实也就是相当于把数组分为有序和无序的两部分)
代码解决:
我们可以设置一个pos,使pos来遍历前一个有序的数组,当从无序数组中拿出一个数据a[i]时,用pos找到这个数的位置,再进行插入
void InsertSort(int* arr,size_t size)
{
assert(arr);
//假设第一个是有序的
for (size_t index=1; index<size; ++index)
{
int pos = index-1;
int tmp = arr[index];
while (pos >= 0 && arr[pos] > tmp)
{
arr[pos+1] = arr[pos];
pos--;
}
arr[pos+1] = tmp;
}
}
直接插入排序的复杂度:
从空间复杂度上看,这种排序算法只需要一个辅助空间来存放临时记录。
从时间复杂度上看,最好的情况是这组数据近似有序或其本身就是有序的,比如上边图示的一组数是{0,2,4,3,5,6},排序时只是多移动了一次,即只需要遍历N+1次。就算数据比较多时,这组数据也是近似有序,那么移动的次数也就只有常数次,因此这种情况下的实践复杂度是O(N)。最坏的情况是数组完全逆序时,假设这组数据时{6,5,4,3,2,0},那么就需要比较n+(n-1)+(n-2)+......(可以理解为是一个等差数列求和),因此这种情况下的时间复杂度为O(N^2)。
二、希尔排序
希尔排序的思想:
希尔排序其实是在插入排序的基础上做了一些优化,即将数组先分组,然后对各组进行排序,即预排序;当进行多次预排序以后数组近似有序,再进行直接插入排序。
这样分组的目的是:当数组完全逆序或近似这种情况时,希尔排序会将大的数据近况向后面移动,小的数据会尽快向前面移动,其实也就是解决了直接插入排序的最坏情况
代码:
void ShellSort(int* arr,size_t size)
{
assert(arr);
//gap是每次分组的相隔的距离,gap越大,预排序后的数据越不近似有序;
//gap越小,挪动的次数太多,因此这里的关键是选取一个合适的gap
//int gap = 3;O
int gap = size;
while (gap > 1)
{
gap = gap/3 + 1; //保证gap最后会为1
//预排序
for (int index=gap; index<size; ++index)
{
int pos = index-gap;
int tmp = arr[index]; //保存当前index位置的数据
while (pos>=0 && arr[pos]>tmp) //升序
{
arr[pos+gap] = arr[pos];
pos -= gap;
}
arr[pos+gap] = tmp;
}
}
}
希尔排序的复杂度:
O(N^1.25 ~ 1.6N^1.25)之间,不会超过O(N^2).
希尔排序比直接进插入排序算法好在哪里?
希尔排序本身就是在插入排序的基础上做的优化了,可能当数据比较少的时候,希尔排序的优势并不明显。但当数据量大的时候,并且这些数据完全逆序或近似逆序时(也就是插入排序最坏的情况),希尔排序就会优于插入排序,因为它的几趟预排序就使这些数据接近有序了。
来源:CSDN
作者:Y-ANG
链接:https://blog.csdn.net/qq_33951180/article/details/53340486