C# 实现希尔排序
过程拆解
假设现有一数组,如下
基本排序代码,如下
static void Main(string[] args)
{
int[] array = new int[] { 5, 4, 5, 2, 3, 6, 1 };//替换代码
BaseSort(array, 3);//替换代码
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i] + " ");
}
Console.ReadKey();
}
public static void BaseSort(int[] array, int gap)
{
for (int i = gap; i < array.Length; i++)
{
int insertValue = array[i];
for (int j = i - gap; j >= 0; j -= gap)
{
if (insertValue < array[j])
{
array[j + gap] = array[j];
array[j] = insertValue;
}
else
{
break;
}
}
}
}
- 将替换代码换成下列代码,运行并分析
int[] array = new int[] { 5, 4, 5, 2, 3, 6, 1 };
BaseSort(array, 3);
//将下标差值为 3 的一组数进行排序
在 下标 3 向前找出 间隔为3 的数 下标 0,并使用插入排序算法进行排序。
在 下标 4 向前找出 间隔为3 的数 下标 1,并使用插入排序算法进行排序。
在 下标 5 向前找出 间隔为3 的数 下标 2,并使用插入排序算法进行排序。
在 下标 6 向前找出 间隔为3 的数 下标 3、下标 0,并且此时下标 0 与下标 3 已经排好序,再使用插入排序算法进行排序。
- 将替换代码换成下列代码,运行并分析
int[] array = new int[] { 1, 3, 5, 2, 4, 6, 5 };
BaseSort(array, 1);
//将下标差值为 1 的一组数进行排序
在 下标 1 向前找出 间隔为1 的数 下标 0,并进行插入排序算法进行排序。
在 下标 1 向前找出 间隔为1 的数 下标 1、下标 0,并进行插入排序算法进行排序。
在 下标 1 向前找出 间隔为1 的数 下标 2、下标 1、下标 0,并进行插入排序算法进行排序。
在 下标 1 向前找出 间隔为1 的数 下标 3、下标 2、下标 1、下标 0,并进行插入排序算法进行排序。
在 下标 1 向前找出 间隔为1 的数 下标 4、下标 3、下标 2、下标 1、下标 0,并进行插入排序算法进行排序。
在 下标 1 向前找出 间隔为1 的数 下标 5、下标 4、下标 3、下标 2、下标 1、下标 0,并进行插入排序算法进行排序。
算法实现
- 希尔排序利用间隔进行分组排序,对直接插入排序算法进行了优化。
- 选择数组长度的一半作为初始间隔长度,并将它们进行排序,之后循环取 n / 2 作为间隔。
- 尽可能的让最后一次执行直接插入排序的时间算法复杂度为O(n)。
代码如下
static void Main(string[] args)
{
int[] array = new int[] { 5, 4, 5, 2, 3, 6, 1 };
ShellSort(array);
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i] + " ");
}
Console.ReadKey();
}
public static void ShellSort(int[] array)
{
for (int gap = array.Length / 2; gap > 0; gap /= 2)
{
//直接插入排序算法
for (int i = gap; i < array.Length; i++)
{
int insertValue = array[i];
for (int j = i - gap; j >= 0; j -= gap)
{
if (insertValue < array[j])
{
array[j + gap] = array[j];
array[j] = insertValue;
}
else
{
break;
}
}
}
}
}
拆分的代码如下
public static void ShellSort(int[] array)
{
for (int gap = array.Length / 2; gap > 0; gap /= 2)
{
InsertSort(array, gap);
}
}
public static void InsertSort(int[] array, int gap)
{
for (int i = gap; i < array.Length; i++)
{
int insertValue = array[i];
for (int j = i - gap; j >= 0; j -= gap)
{
if (insertValue < array[j])
{
array[j + gap] = array[j];
array[j] = insertValue;
}
else
{
break;
}
}
}
}
复杂度与稳定性
- 最优时间复杂度:当间隔为1,且排好序的情况,只需要经历插入排序中第1个 for循环 。
- 最差时间复杂度:当数组是倒序的,通过希尔排序中的间隔操作后,可以减少插入排序中第2个 for循环 的执行次数。因此实际排序的时间与直接插入排序的最差时间复杂度是一样的。
- 平均时间复杂度:主要取决于间隔的取值
- 空间复杂度:需要借助 insertValue 变量用来记录进行比较的数值
- 稳定性:经过排序算法后,前面的数值排在了后面(如:5)
因为作者精力有限,文章中难免出现一些错漏,敬请广大专家和网友批评、指正。