一.插入排序
1.插入排序介绍
插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。 按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序 。
2.代码
1.单趟排序(即插入一个数据)
以从小到大的排序为例。
int end; //end为原来的有序的序列的最后一个数字的下标
x = a[end + 1]; //x为需要插入的数据
while (end >= 0)
{
//当x比序列的最后一个数字要小时,最后一个数字往后挪一个位置
//当x比序列的倒数第二个数也小时,倒数第二个数字也往后挪一个位置
//以此类推,直到x比某个数字大时,跳出循环
if (a[end] > x)
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
//此时,如果x比原来的序列的所有数字都小,那么end为-1,end+1为0,即x会插入到a[0]的位置
//否则,x会插入到比x小的数字的后面,比x大的数字的前面
a[end + 1] = x;
这样我们就实现了将一个数字插入一个有序数列。
2.完整排序
那么,在实现了单趟排序的基础上,我们可以实现将一个无序的数组进行从大到小或者从小到大的排序。
我们还是以从小到大的排序为例。(要想实现从大到小,改变大于小于号即可)
void InsertSort(int* a, int n)
{
assert(a); //断言
int end = 0;
int x = 0;
for (end = 0; end <= n - 2; end++)
{
//当end为数组的倒数第二个元素时,x为数组的最后一个元素,所以end <= n - 2
x = a[end + 1];
while (end >= 0)
{
if (a[end] > x)
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = x;
}
}
3.运行结果
二.希尔排序
1.概念
希尔排序(Shell Sort)属于插入排序的一种,也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。
将一列数分为gap组,比如gap为3时,分组如下:
将每一组内分别进行插入排序,gap为3时,即需要进行3次插入排序的过程。每一组插入排序结束后,其组内的数字就是升序。
比如:红箭头所指的一组:1 3 9;
蓝箭头所指的一组:2 5 6;
绿框的一组:4 7 8;
总的数列:1 2 4 3 5 7 9 6 8;
当gap组数据分别进行插入排序之后,该数列就变得更加相对有序了。
2.代码
//希尔排序
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap /= 2;
//gap不断变小,直至为1
int j = 0;
//将gap组数据分别进行插入排序
for (j = 0; j < gap; j++)
{
int end = 0;
//一组数据的插入排序
for (end = j; end < n - gap; end += gap)
{
int x = a[end + gap];
while (end >= 0)
{
if (a[end] > x)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = x;
}
}
}
}
3.代码略作改动
实质是:2中的代码是将gap组一组一组排序,而下面的代码中,则是按照顺序一个一个排序。
//希尔排序稍加改动(减少了循环嵌套,代码简化,但效率并未优化)
void ShellSort2(int* a, int n)
{
int gap = n;
while (gap>1)
{
gap /= 2;
int i = 0;
for (i = 0; i < n - gap; i++)
{
int end = i;
int x = a[end + gap];
while (end >= 0)
{
if (a[end] > x)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = x;
}
}
}
4.运行结果