希尔排序,是改进的插入排序。其核心思想是:给定一个间隔gap,按照这个间隔将待排序数组的数,跳着“取出来”,形成一个新待排序数组,然后对这个新数组进行插入排序。间隔缩小,重复上述过程,知道gap==1。
希尔排序演示:
假设间隔gap=4,第一轮
然后,gap对半,gap=2,重复上述,直到gap==1,结束排序。
我们开始写算法程序吧。
首先,这个是改进的插入排序,我们先把插入排序写好。在插入排序的基础上,改进。
#include<iostream>
void swap(int a[], int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
static void Shellsort(int a[], int length);//函数头
static void Shellsort(int a[], int length) {
for (int i = 1; i < length; i++) {//why i++
for (int j = i; j > 0; j --) {
if (a[j] < a[j - 1]) {
swap(a, j, j - 1);
}
}
}
}
int main() {
using std::cout;
int a[] = { 9,6,11,3,5,12,8,7,10,15,14,4,1,13,2 };
int length = sizeof(a) / sizeof(a[0]);
Shellsort(a, length);
for (auto i : a) cout << i << " ";
//cin.get();//在按下enter键之前,任何键击将不被发送给程序
return 0;
}
根据希尔排序思想,要点1:设置间隔。
·从简单到复杂,一点点完成。
假设我们把间隔gap定位4,先完成间隔为4的第一次排序。其实就是把插入排序的间隔为1,改为了间隔为4。所以,外面的循环从gap开始,代替了1,里面的内循环,j>0改为j>gap-1,j–改为j=j-gap。
static void Shellsort(int a[], int length) {
int gap=4;
for (int i = gap; i < length; i++) {//why i++
//间隔不再是1了,改为gap=4,所以此时j>gap-1,防止越界
for (int j = i; j > gap - 1; j -= gap) {
if (a[j] < a[j - gap]) {
swap(a, j, j - gap);
}
}
}
}
完成了第一次循环,接下来就很简单了。就是不断把间隔缩小,一直到gap=1。很容易想到,再加一个gap的for循环,控制gap。
所以,最终的希尔排序就是这样。
我们设定为间隔为4的希尔排序如下:
static void Shellsort(int a[], int length) {
for (int gap = 4; gap > 0; gap /= 2) {
for (int i = gap; i < length; i++) {//why i++
for (int j = i; j > gap - 1; j -= gap) {
if (a[j] < a[j - gap]) {
swap(a, j, j - gap);
}
}
}
}
}
是不是,一步一步就写出来啦,万事开头难。
简单的优化
对希尔排序进行优化,其实就是对他的间隔设置进行优化,如何找到“恰到好处”的间隔,能让排序效率更快一点。
间隔设置
♣ 第一种:常见的以待排序数组的一半,不断缩小,对半。gap==N/2(N为数组长度)
static void Shellsort(int a[], int length) {
//将length/2改为位运算:右移一位length >> 1,给面试官的印象更好
for (int gap = length >> 1; gap > 0; gap /= 2) {
for (int i = gap; i < length; i++) {//why i++
for (int j = i; j > gap - 1; j -= gap) {
if (a[j] < a[j - gap]) {
swap(a, j, j - gap);
}
}
}
}
}
小tips:将int gap = length ;改为位运算,右移一位。应该给面试官的印象更好一点。
♣ 第二种:Knuth序列
gap=1;
gap=3*gap+1
当gap超过整个数组的1/3。就不合适了。
间隔,采用Knuth序列要比采用N/2,效率要高一些。
static void Shellsort(int a[], int length) {
int h = 1;
while (h <= length/3)
{
h = h * 3 + 1;
}
//将length/2改为位运算:右移一位length >> 1,给面试官的印象更好
for (int gap = h; gap > 0; gap =(gap-1)/3) {
for (int i = gap; i < length; i++) {//why i++
for (int j = i; j > gap - 1; j -= gap) {
if (a[j] < a[j - gap]) {
swap(a, j, j - gap);
}
}
}
}
}
End.