希尔排序(Shell's Sort)

希尔排序又叫缩小增量排序,是1959年 Shell 发明的第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。

这种排序是把一定间隔的数当做一个数组,在每个分好的数组里进行插入排序,再缩小间隔重复步骤,直到间隔为1,直接插入排序所有数。

这样开始每组数据量都比较小,可以发挥插入的优势,排序速度比较快,在缩小间隔后,虽然个数增加,但是因为之前已经粗略排了序,有序性比较高,也能发挥插入的优势,提高效率。

那么这个间隔(增量)取多少比较好?

增量的取法有各种方案。最初 Shell 提出取 increment=n/2 向下取整,increment=increment/2 向下取整,直到 increment=1。但由于直到最后一步,在奇数位置的元素才会与偶数位置的元素进行比较,这样使用这个序列的效率会很低。后来 Knuth 提出取 increment=n/3 向下取整 +1 ,还有人提出都取奇数为好,也有人提出 increment 互质为好。应用不同的序列会使希尔排序算法的性能有很大的差异。 这里使用 n/3 向下取整 +1 的方法

举个栗子来理解:

0 1 2 3 4 5 6 7
12 8 5 7 14 1 6 2

第一趟,取增量 increment  =  n/3 + 1 = 3,将数列划分为以 3 为间隔的数列(这里用同种颜色表示同一序列)

0 1 2 3 4 5 6 7
12 8 5 7 14 1 6 2

在每个序列中进行插入排序

0

1 2

3

4 5

6

7

6

8 5

7

14 1

12

2
0

1

2 3

4

5 6

7

6

2

5 7

8

1 12

14

0 1

2

3 4

5

6 7
6 2

1

7 8

5

12 14

第一趟结束后的排序

0 1 2 3 4 5 6 7
6 2 1 7 8 5 12 14

再开始第二趟之旅,这次我们取增量为 increment = increment/3 + 1 = 2(都是向下取整),为了看得清咱一组一组来

0

1

2

3

4

5

6

7
6 2 1 7 8 5 12 14

排序后结果

0

1

2

3

4

5

6

7

1

2

6

7

8

5

12

14

同样的,另一组排序

0

1

2

3

4

5

6

7

1

2

6

5

8

7

12

14

上面那个就是第二趟排序结果啦,最后第三趟排序,也就是增量为1(increment = increment/3 + 1 = 1),直接插入排序就可得到最终结果

0

1

2

3

4

5

6

7

1

2

5

6

7

8

12

14

主要代码

其实就是直接插入排序的外层多了个间隔 increment 的循环

void shell_sort(int a[], int n)
{
	int increment = n;
	do
	{
		increment = increment/3 + 1;
		for(int i=increment;i=0 && a[flag]>t)
			{
				a[flag+increment] = a[flag];
				flag -= increment;
			}
			a[flag+increment] = t;
		}
	}while(increment>1);
}

运行过程

希尔排序(Shell's Sort)_第1张图片

你可能感兴趣的:(算法总结,插入排序,希尔排序)