排序的分类
这篇先从插入排序说起
直接插入排序
顾名思义,就是将一个数直接插入到对的位置,这个算法的思想就像我们打扑克时
我们拿到一个数(抽了一张牌),从后先前,将它插入到对的地方
- 从第一个数开始,这个数可以认为已经被排序
- 取出下一个数, 将这个数插入到前面以有序的序列中
- 如果这个数,小于前面的数,将前面的数向后移动,循环这个动作,直到插入合适的位置
//直接插入排序
//O(N*N)
void InsertSort(int* a,size_t n)
{
assert(a);
//从前向后抽排
for (int i = 0; i<n-1; i++)
{
int end = i;
//取出待插入值
int tmp = a[end + 1];
//从end开始,从后向前,遇到比插入值大的向后移一位
while (end >= 0 && a[end] > tmp)
{
a[end + 1] = a[end];
--end;
}
//找到要插入的位置,插入;
a[end + 1] = tmp;
}
}时时间复杂度O(n^2)
// 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
// 平均时间复杂度 ---- O(n^2)
插入排序不适合对于数据量比较大的排序应用
希尔排序
希尔排序又称为“缩小增量排序”,至于为什么叫缩小增量排序,我们一会就会解释
希尔排序是对直接插入排序的改进,
它的基本思想是:先将整个待排序列分割成若干个子序列,分别对子序列进行组内直接插入排序(预排序),然后再对整个序列,以组为单位,进行直接插入排序
排序过程如下图所示:d表示增量
希尔排序的特点是:它的子序列的划分不是简单的“逐段分割”,而是将相隔某个“增量”的数据组成一个子序列。
过程:
- 先将序列以合适的增量进行分组
- 将分好的组,分别进行组内的排序
- 以组内第一个元素为值进行比较,将全部序列排序
- 然后缩小增量,重复上面三个步骤,直到增量为1
上面的例子,第一趟的排序增量为4,第二趟排序的增量为2,每一次的增量都在减小,直到最后一次增量为1,所以这就是为什么这种排序又叫“缩小增量排序”的原因
由于前两趟的插入排序中,在子序列的内部排序中,都是和自己隔了几个增量的前一个数据进行比较的,因此较小的数据就不是一步一步的往前移动的,而是跳跃式地往前移动,当最后一趟增量为1的插入排序时,序列已基本有序了,只要再做少量的比较和移动就可以完成整体的排序
void ShellSort(int*a, size_t n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (size_t i = 0; i < n - gap; ++i)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0 && a[end]>tmp)
{
a[end + gap] = a[end];
end -= gap;
}
a[end + gap] = tmp;
}
}
}