一言
越想贴近事实,不明白的事情就越多
直接插入排序
直接插入排序是一种简单的排序方法,它的思路就像是插扑克牌一样,每次排序一个,最终排序完成。
时间复杂度:O(N^2)
具体思路如下:
- 两层循环,外循环遍历整体,内循环遍历已排序的地方。
- 先用一个变量将要排序的数保存下来。
- 内循环用来判断,如果符合条件,就移动,不符合就退出。
- 最后的时候将排序的数加上去。
以下为单步的图解如下:
代码如下:
void insertSort(int* arr, int n)
{
for (int i = 0; i < n - 1; i++)
{
int tmp = arr[i + 1];
int end = i;
while (end >= 0)
{
if (tmp < arr[end])
{
arr[end + 1] = arr[end];
end--;
}
else
{
break;
}
}
arr[end + 1] = tmp;
}
}
希尔排序
希尔排序是插入排序的进阶,它相比于直接插入排序更加高效但是也更抽象。
希尔排序分为两个阶段:
- 预排序:使数组趋向于有序
- 直接插入排序:在预排序的基础上再插排会更加高效
时间复杂度:O(N^1.25),它的计算比较复杂
它的思路是这样的:
- 首先定义一个gap大小,对数据进行分组,即每隔gap个数据为一组,gap大小的定义后面会讲。
- 对每一组的数据进行直接插入排序,这也就是预排序的过程。
- 排完序以后对gap进行减小,然后再排序。
- 最后当gap == 1的时候,在进行排序就相当于进行直接插入排序了,不管前面预排序如何,都会在这一步排序完成。
图解如下:
gap的变化有很多种选择,但是目前并没有官方的解释说哪一种效率最高。目前通用的是使用/=2或者 /3 +1 。
具体代码如下:
void ShellSort(int* arr, int n)
{
int gap = n / 2;
while (gap > 0)
{
for (int i = 0; i < gap; i++)
{
for (int j = i; j < n - gap; j+=gap)
{
int end = j;//内部用直接插入排序实现的
int tmp = arr[end + gap];
while (end >= 0)
{
if (tmp < arr[end])
{
arr[end + gap] = arr[end];
end-=gap;
}
else
{
break;
}
}
arr[end + gap] = tmp;
}
}
gap /= 2;
}
}
上述代码是比较好理解的版本,但是循环嵌套了太多,下面是优化版,需要好生理解一下。
void ShellSort(int* arr, int n)
{
int gap = n / 2;
while (gap > 0)
{
for (int j = 0; j < n - gap; j++)
{
int end = j;//内部用直接插入排序实现的
int tmp = arr[end + gap];
while (end >= 0)
{
if (tmp < arr[end])
{
arr[end + gap] = arr[end];
end-=gap;
}
else
{
break;
}
}
arr[end + gap] = tmp;
}
gap /= 2;
}
}
纸上得来终觉浅,绝知此事要躬行。
感谢各位的佬观看,点个关注再走吧ლ(°◕‵ƹ′◕ლ)