数据结构 - 希尔排序
2013-06-13 18:57
169 查看
希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
原始的算法实现在最坏的情况下需要进行O(n2)的比较和交换。V. Pratt的书对算法进行了少量修改,可以使得性能提升至O(n log2 n)。这比最好的比较算法的O(n log n)要差一些。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n2)的排序(冒泡排序或插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。
一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用
附:看到某书上给出的希尔排序编码如下
void ShellSort(int a[], int left, int right)
{
int len = right - left + 1;
int d = len;
while (d > 1)
{
d = (d + 1) / 2;
for (int i = left; i < right + 1 - d; i++)
{
if (a[i + d] < a[i])
{
int tmp = a[i + d];
a[i + d] = a[i];
a[i] = tmp;
}
}
}
}
//参数不一样,思想一样
void shell_sort(int a[], int n)
{
int d = n;
while (d > 1)
{
d = (d + 1) / 2;
for (int i = 0; i < n - d; i++)
{
if (a[i + d] < a[i])
{
int tmp = a[i + d];
a[i + d] = a[i];
a[i] = tmp;
}
}
}
}看起来写的不错,代码比较简洁,对吗?测试数据
对,结果反映它是错的。返回去看代码,手动过一遍测试,代码中的排序是插入排序么?
倒是挺像交换排序,因为它每次比较的是前后两个数,而并非是插入一个数并完成排序。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
原始的算法实现在最坏的情况下需要进行O(n2)的比较和交换。V. Pratt的书对算法进行了少量修改,可以使得性能提升至O(n log2 n)。这比最好的比较算法的O(n log n)要差一些。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n2)的排序(冒泡排序或插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。
一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用
i += step_size而不是
i++)。
#include <stdio.h> void ShellSort(int a[], int n) { int gap, i, j, temp; //gap用来控制移动距离(由大到小,直到0) for (gap = n / 2; gap > 0; gap /=2) { //这里i定义为每组数据的第二个,默认第一个为有序 //i < n : 由于以下for循环每次对每组数据只做一次插入排序(即将第二个数据插入) //(曾考虑i只需要到后一个gap即可停止循环,则结果是从第三个数开始都不会执行排序) for (i = gap; i < n; i++) { temp = a[i]; //这里将简单插入排序浓缩 for (j = i - gap; j >= 0 && a[j] > temp; j -= gap) a[j + gap] = a[j]; a[j + gap] = temp; } } } int main() { int a[] = {4, 2, 7, 5, 3, 8, 9, 0, 6, 1}; //int a[] = {13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10}; //int a[] = {7, 7, 0, 0, 3, 0, 6, 6, 3}; ShellSort(a, 10); for (int i = 0; i < 10; i++) printf("%d\t", a[i]); printf("\n"); return 0; }
附:看到某书上给出的希尔排序编码如下
void ShellSort(int a[], int left, int right)
{
int len = right - left + 1;
int d = len;
while (d > 1)
{
d = (d + 1) / 2;
for (int i = left; i < right + 1 - d; i++)
{
if (a[i + d] < a[i])
{
int tmp = a[i + d];
a[i + d] = a[i];
a[i] = tmp;
}
}
}
}
//参数不一样,思想一样
void shell_sort(int a[], int n)
{
int d = n;
while (d > 1)
{
d = (d + 1) / 2;
for (int i = 0; i < n - d; i++)
{
if (a[i + d] < a[i])
{
int tmp = a[i + d];
a[i + d] = a[i];
a[i] = tmp;
}
}
}
}看起来写的不错,代码比较简洁,对吗?测试数据
{4, 2, 7, 5, 3, 8, 9, 0, 6, 1};结果如下图:
对,结果反映它是错的。返回去看代码,手动过一遍测试,代码中的排序是插入排序么?
倒是挺像交换排序,因为它每次比较的是前后两个数,而并非是插入一个数并完成排序。
相关文章推荐
- 【数据结构和算法】排序算法之四:希尔排序
- java 数据结构-->希尔排序
- 小蚂蚁学习数据结构(36)——插入排序中的希尔排序
- [数据结构]插入排序与希尔排序
- 《常见算法和数据结构》元素排序(2)——希尔排序(动画)
- 【数据结构】Java实现各类经典排序算法——插入排序、希尔排序
- 数据结构之希尔排序(谢尔排序)
- 【数据结构和算法】排序算法之四:希尔排序
- 数据结构排序--直接插入和希尔排序
- 数据结构-排序算法-希尔排序
- 数据结构-希尔排序
- 开始学数据结构——(六):希尔排序
- 数据结构-希尔排序
- 数据结构-排序算法详解(插入排序,希尔排序,堆排序,归并排序,快速排序,桶式排序)
- 第16周SHH数据结构-【项目1-验证算法(2)希尔排序】
- java 数据结构基本算法希尔排序
- 数据结构之内部排序--希尔排序
- python数据结构之希尔排序
- [golang] 数据结构-希尔排序
- 数据结构之插入排序与希尔排序