直接插入排序与希尔排序都是插入排序,而希尔排序则是对直接插入排序的优化。
1、直接插入排序
直接插入排序就是将一个数从一个数组后面依次向前插入,比较大小,将数组的数一个个后移直到能插入到合适的位置。举个例子:
初始 :1 2 4 5 6 7 8 9 3
3是要向前面一个数组插入的数字,依次将3与9,8,7,6,5,4作比较,依次将比3大的数字后移,直到与2比较时发现比2大,便将3插入到2后面一个位置。
结果:1 2 3 4 5 6 7 8 9
这便是插入排序的基本思想,下面用代码实现一下这个过程:
void InsertSort(int* a, int n)
{
int end ;
int tmp = a[end + 1];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + 1] = a[end];
end--;
}
else
{
break;//两种情况:第一是tmp在中间找到位置,第二是tmp在下标为0的位置
//必须要跳出循环的原因是如果tmp最后要在下标为0的位置,循环条件已经不满足
//提前结束循环从而导致tmp没有被赋值到下标为0处
}
}
a[end + 1] = tmp;
}
以上是直接插入排序单趟的情况,而一般的情况都是以下所示:
初始:9 1 6 3 8 4 7 5 2
将这个数组进行直接插入排序,也就是开始end在下标为0的位置,将1向前插入,然后end依次向后移,层层递进,进行多趟插排,代码实现只需在单趟的基础上套上循环控制end位置即可。
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)//i是end的位置,end最后位置在下标n-2处
{
//[0-end]有序,将end+1的值插入
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + 1] = a[end];
end--;
}
else
{
break;//两种情况:第一是tmp在中间找到位置,第二是tmp在下标为0的位置
}
}
a[end + 1] = tmp;
}
}
以上就是直接插入排序的实现。如果数组越接近有序那么排序速度就越快,但面对大量无序的数据它的效率就大大降低了,下面介绍的希尔排序便优化了这个问题。
2、希尔排序(缩小增量排序)
希尔排序的基本思想:先取定一个整数设为gap,将所有的数据分为gap个组,所有相距为gap的数据为一个组,先将每个组的数据进行排序,最后再缩小gap的值重复上述操作直到gap为1完成排序。举个例子:
初始: 9 1 2 5 7 4 8 6 3 5
gap=5:4 1 2 3 5 9 8 6 5 7
gap=2:2 1 4 3 5 6 5 7 8 9
gap=1:1 2 3 4 5 5 6 7 8 9
gap>1时的排序都是预排序,是为了让数组更加接近有序,而最后gap=1时的排序便是直接插入排序。
下面用代码实现这个过程:
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;//保证最后一次一定是1,进行最后一次插入排序
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;
}
}
}