2014.06.17 02:43
简介:
希尔排序是插入排序的改进版。交换排序的目的,是通过交换,将逆序数降低为0。每交换一对相邻元素,逆序数变化为1。如果交换的元素不相邻,则逆序数的变化可能就大于1。希尔排序的思路,就是通过交换离得更远的两个元素,让逆序数更快地变为0(当然,并不总是管用)。
描述:
我们定义一个间隔k,每隔k各元素选取一次,可以选出一个子数组。那么可以找出k个这样的子数组。对于每个子数组进行插入排序,这样的插入排序中,每交换一次减少的逆序数可能大于1,从而提高效率。但排序以后k个子数组之间没有进行比较,因此我们再选取另一个间隔k’,再来一轮。实际上,这样的间隔序列可以自己定义,只要合理即可。通过查资料可以找到前辈们总结的比较靠谱的间隔序列。一种简单直观的间隔序列,就是{n / 2, n / 4, n / 8, ..., 1}。这是明显的折半,但注意不要把顺序反过来。理由很明显:如果你一开始就选1作为间隔,那就是插入排序,剩余的间隔排序就没有意义了,效率自然也不会提高。关于希尔排序的复杂度,不一定是O(n^2),要根据选取的间隔序列来分析。
实现:
1 // My implementation for shell sort. 2 #include <iostream> 3 #include <vector> 4 using namespace std; 5 6 void shellSort(vector<int> &v) 7 { 8 int n, i, j; 9 int tmp; 10 int increment; 11 12 n = (int)v.size(); 13 for (increment = n / 2; increment > 0; increment /= 2) { 14 for (i = increment; i < n; ++i) { 15 tmp = v[i]; 16 for (j = i; j >= increment && v[j - increment] > tmp; j -= increment) { 17 v[j] = v[j - increment]; 18 } 19 v[j] = tmp; 20 } 21 } 22 } 23 24 int main() 25 { 26 vector<int> v; 27 int n, i; 28 29 while (cin >> n && n > 0) { 30 v.resize(n); 31 for (i = 0; i < n; ++i) { 32 cin >> v[i]; 33 } 34 shellSort(v); 35 for (i = 0; i < n; ++i) { 36 cout << v[i] << ' '; 37 } 38 cout << endl; 39 } 40 41 return 0; 42 }