一、插入法排序
1.基本思想
就是把待排序的数据按大小逐个插入到一个已经排好序的有序序列中,直到所有的数据都插完,得到一个有序序列。
我们平常玩扑克牌的时候用的就是这个道理:
2.动画演示
从动画可以看出:
插入的数据(a)和前面的数从后往前进行比较,如果插入的这个数小于前面的数,那么前面的数就往后移,直到前面的数(b)小于插入的这个数,那么a就放在b后面。
具体思路:
3.代码实现
先写内层循环:
int end;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
end--;
}
else
{
a[end + 1] = tmp;
break;
}
}
再写外层循环:
for (int i = 0; i < n - 1; i++)
这里是n - 1的原因是:最后一个数已经排好了,不需要再管最后一个数了。
但是这样会有一个问题,还是上面的数组,如果插入的数是0,那么end--,最后end= -1,不会进行else的语句
所以我们把a[end+1]=tmp, 写到while循环外面。
最终代码:
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;//直接给一个数组,不能确定是有序的,所以从第一个数开始,end随数组的增大往后移
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
二、希尔排序
希尔排序的最基本思想和插入排序是一样的,只不过插入排序是一个一个进行比较,而希尔排序是跳着进行比较。
1.动图演示
预排序:分组插入排序。
目标:大的更快换到后面的位置,小的更快换到前面的位置。
内层循环:
int end;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = a[end];
外层循环:
for(int j = 0; j<gap; j++)//代表一共进行gap组
{
for(int i = j; i<n - gap; i+=gap)
{
}
}
2.整体代码
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;//1是为了保证最后一次gap的取值为1,在gap等于1之前都为预排序
for (int j = 0; j < gap; j++)
{
for (int i = j; i < n - gap; i += gap)
{
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;
}
}
}
}
可以看到上面的循环式四层,我们可以把它转换成三层
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap /= 2;
gap = gap / 3 + 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;
}
}
}
over~