您的位置:首页 > 其它

排序算法---直接插入排序和希尔排序

2016-11-26 13:00 537 查看
排序算法大致可分为:

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).

希尔排序比直接进插入排序算法好在哪里?

希尔排序本身就是在插入排序的基础上做的优化了,可能当数据比较少的时候,希尔排序的优势并不明显。但当数据量大的时候,并且这些数据完全逆序或近似逆序时(也就是插入排序最坏的情况),希尔排序就会优于插入排序,因为它的几趟预排序就使这些数据接近有序了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐