希尔排序(Shell Sort)
程序员文章站
2024-03-19 13:05:22
...
#include<bits/stdc++.h>
using namespace std;
/*
说明:
下面的内容全是按照升序排序来写的。
*/
/*
逆序对:
对于下标i < j,若arr[i] > arr[j],则称arr[i]和arr[j]是一个逆序对。
在排序过程中,最终的目的就是需要消除全部的逆序对。
简单排序的弊端:
在简单排序中,以交换相邻的两个元素的算法每次都仅能消除一个逆序对,
所以提升排序效率的方法是每次交换两个元素时能消除多个逆序对。
*/
/*
希尔排序:
希尔排序是插入排序的改进,插入排序每次仅交换相邻的两个元素。希尔
排序中多次调用插入排序,但排序的间隔不再是1,每趟排序交中进行交换
的是一定间隔的排序。使其能做到交换两个元素时能消除多个逆序对。但
是最后一趟插入排序的间隔一定是1,也就是说最后一趟还是普通的插入排
序。这样虽然是三重循环,但元素真正交换的次数小于简单排序。由此希
尔排序中最重要的就是设置这种间隔,即增量序列的选择,常用的有两个排
序效率较高的增量序列:Hibbard序列和Sedgewick序列。
*/
/*
Hibbard序列:
(1 << (++k)) - 1
*/
vector<int> hibbardSequence(int n)
{
vector<int> seq;
int temp = 1, k = 1;
while(temp < n && temp > 0)
{
seq.push_back(temp);
temp = (1 << (++k)) - 1;
}
return seq;
}
/*
Sedgewick序列:
i从1开始,j从2开始,
9*((1<<(i*2))-(1<<i))+1 > (1<<(j*2))-3*(1<<j)+1 :取后者,j++
9*((1<<(i*2))-(1<<i))+1 < (1<<(j*2))-3*(1<<j)+1 :取前者,i++
*/
vector<int> sedgewickSequence(int n)
{
vector<int> seq;
int temp = 1, i = 1, j = 2, a, b;
while(temp < n && temp > 0)
{
seq.push_back(temp);
a = 9 * ((1 << (i * 2)) - (1 << i)) + 1;
b = (1 << (j * 2)) - 3 * (1 << j) + 1;
a < b ? temp = a : temp = b;
a < b ? i++ : j++;
}
return seq;
}
void shellSort(int *arr, int len, vector<int> (*getSeq)(int))
{
vector<int> seq = getSeq(len);
int n = seq.size(), begin, temp, j, d;
for(int i = n - 1; i >= 0; i--) //增量序列
{
d = seq[i]; //增量
for(begin = d; begin < len; begin++) //插入排序
{
temp = arr[begin];
for(j = begin - d; j >= 0 && arr[j] > temp; j -= d)
arr[j + d] = arr[j];
arr[j + d] = temp;
}
}
}
int main()
{
int arr[10];
srand((unsigned)time(NULL));
for(int i = 0; i < 10; i++)
arr[i] = rand() % 10;
for(int i = 0; i < 10; i++)
cout << arr[i] << " ";
cout << endl;
shellSort(arr, 10, sedgewickSequence);
for(int i = 0; i < 10; i++)
cout << arr[i] << " ";
return 0;
}