目录
直接插入排序
直接插入排序是一种简单的插入排系法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。也就是将一个有几个元素的待数组看成一个有序表和一个无序表,开始时有序表中只有1个元素,无序表中有n-1个元素,排序过程就是每次从无序表中取出第1个元素,将它插入到有序表中的适当位置,成为一个新的有序表,重复n-1次就可完成排序。
重复以上过程
插入排序代码
//插入排序
void insertsort(int* a, int n)
{
for (int i = 0; i < n ; ++i)
{
int end=i;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
int main()
{
int a[] = { 104,33,12,32,56,77,82 };
int len = sizeof(a) / sizeof(a[0]);
shellsort(a, len);
for (int i = 0; i <len; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
时间复杂度和稳定性
直接插入排序的时间复杂度是O(N^2):
假设被排序的数列中有N个数,遍历一趟时间复杂度是O(N),需遍历多少次呢?N-1次,因此,其时间复杂度是O(N2)。直接插入排序是稳定的算法,它满足稳定算法的定义:假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!
插入排序在小规模数据或者基本有序的数组时十分高效,因为这时数据移动少,那么如何使它在较大规模的数组并且数组数据无序度较高时也非常有效呢?
在熟悉插入排序后我们来学习插入序的改进版希尔排序(又称缩小增量排序)。
希尔排序
基本思想:
1、先选定一个整数gap(小于数组元素个数)把特排序数组中分成gap组,所有距离为gap的数据分在同一组内并对每一组内的数据进插入排序,然后再缩小gap做为增量,重复以上操作
2.当gap缩小到1时,就是所有的数据都分在一组,这时数组已经接近有序了, 插入排序对接近有序的数组很高的排序效率。
这时有同学会问为什么希尔排序又叫缩小增量排序?就这是因为gap从一个较大的值,缩小到一个较小的值,前期gap较大是为了让较大的数据能快速挪到相应位置附近减少对数据的挪动次数。
实现过程:
首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高。
对每个小组进行插入排序后,各个小组就变成了有序的了(整体不一定有序)
然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比较高
同理对每个分组进行排序(插入排序),使其每个分组各自有序
最后设置增量为上一个增量的一半:1,则整个数组被分为一组,此时,整个数组已经接近有序了,插入排序效率高。
代码实现:
对各个组进行插入的时候并不是先对一个组进行排序完再对另一个组进行排序,而是轮流对每个组进行插入排序
void shellsort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 2;
for (int i = 0; i < n - gap; ++i)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
int main()
{
int a[] = { 104,33,12,32,56,77,82 };
int len = sizeof(a) / sizeof(a[0]);
shellsort(a, len);
for (int i = 0; i <len; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
希尔排序的特性总结:
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的 希尔排序的时间复杂度都不固定。
希尔排序的其他例子