希尔排序
1 基本原理
1 核心思想:希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。
2 算法分析:
希尔排序是把序列按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个序列恰好被分成一组,排序便终止。
2 实例说明
如上图所示,以一组数据{9,1,2,5,7,4,8,6,3,5} 为例,进行直接插入排序的算法演示:
- 令步长gap=5,则原数组分为[9,4],[1,8],[2,6],[3,5],[5,7]五个数组,分别进行直接插入排序,数组变为[4,1,2,3,5,9,8,6,5,7]。
- 令步长gap=2,则原数组分为[4,2,5,8,5]和[1,3,9,6,7]两个数组,分别进行直接插入排序,数组变为[2,1,4,3,5,6,5,7,8,9]。
- 令步长gap=1,对数组进行直接插入排序,完成排序。
3 代码实现
// 希尔排序(C++)
void ShellSort(vector<int> &vi)
{
int j, gap;
for (gap = vi.size() / 2; gap>0; gap /= 2)
{
for (j = gap; j<vi.size(); j++)
{
if (vi[j]<vi[j - gap]) //组内元素进行直接插入排序
{
int temp = vi[j];
int k = j - gap;
while (k >= 0 && vi[k]>temp)
{
vi[k + gap] = vi[k];
k -= gap;
}
vi[k + gap] = temp;
}
}
for (auto x : vi)
cout << x << " ";
cout << endl;
}
}
4 性能分析
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。
希尔排序的时间复杂度与步长取值有关。
- 1 时间复杂度:
希尔增量时间复杂度为O(n^2),而Hibbard增量的希尔排序的时间复杂度为O( n^1.5 ),希尔排序时间复杂度的下界是O(n*log2n)。 - 2 空间复杂度:
希尔排序过程中用到了直接插入排序,需要临时变量存储待排序元素,因此空间复杂度为O(1)。 - 3 算法稳定性:
希尔排序是不稳定的算法,对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。