希尔排序python 图解_排序算法分析【二】:希尔排序(附Python&C++代码)

希尔排序

也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率;

2、插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位;

算法原理

基础是插入排序,我们先看图,图片动态展示:

这个图太快了还是不知道他在干嘛,在给一张图(图片均来自互联网):

步长选择

希尔排序中步长的选择是重中之重!【来自于维基百科】

1、最终步长必须为1,任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

2、初始步长选择:Donald Shell 最初建议步长选择为

并且对步长取半直到步长达到 1。虽然这样取可以比

类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。

希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。

已知的最好步长串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),该串行的项来自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 这两个算式。这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长串行的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。

另一个在大数组中表现优异的步长串行是(斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的幂进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)

图解

如图2:步长为3时,我们把数据分组为:a[1], a[4], a[7]与a[2], a[5], a[8]与a[3], a[6], a[9],我们分别对这三组进行插入排序;

步长为2时,我们继续分组为:a[1], a[3], a[5], a[7], a[9]与a[2], a[4], a[6], a[8],我们分别对这两组排序;

步长为1时,进行真正的插入排序,但由于大量数据以有序,所以实际时间复杂度会小于原始的插入排序。

算法实现

Python实现:

#-*- encoding: utf-8 -*-

def shell_sort(st_bf):

# 希尔排序

lens = len(st_bf)/2

steps = [lens]

while (lens > 1):

lens /= 2

steps.append(lens)

for step in steps:

print 'steps = {}'.format(step)

for i in xrange(step, len(st_bf)):

temp = st_bf[i]

j = i - step

while j >= 0 and st_bf[j] > temp:

st_bf[j+step] = st_bf[j]

j -= step

st_bf[j+step] = temp

print st_bf

st_bf = [6, 5, 3, 1, 8, 7, 2, 4, 2]

shell_sort(st_bf)

结果为:

>>> ================================ RESTART ================================

>>>

steps = 4

[6, 5, 3, 1, 8, 7, 2, 4, 2]

[6, 5, 3, 1, 8, 7, 2, 4, 2]

[6, 5, 2, 1, 8, 7, 3, 4, 2]

[6, 5, 2, 1, 8, 7, 3, 4, 2]

[2, 5, 2, 1, 6, 7, 3, 4, 8]

steps = 2

[2, 5, 2, 1, 6, 7, 3, 4, 8]

[2, 1, 2, 5, 6, 7, 3, 4, 8]

[2, 1, 2, 5, 6, 7, 3, 4, 8]

[2, 1, 2, 5, 6, 7, 3, 4, 8]

[2, 1, 2, 5, 3, 7, 6, 4, 8]

[2, 1, 2, 4, 3, 5, 6, 7, 8]

[2, 1, 2, 4, 3, 5, 6, 7, 8]

steps = 1

[1, 2, 2, 4, 3, 5, 6, 7, 8]

[1, 2, 2, 4, 3, 5, 6, 7, 8]

[1, 2, 2, 4, 3, 5, 6, 7, 8]

[1, 2, 2, 3, 4, 5, 6, 7, 8]

[1, 2, 2, 3, 4, 5, 6, 7, 8]

[1, 2, 2, 3, 4, 5, 6, 7, 8]

[1, 2, 2, 3, 4, 5, 6, 7, 8]

[1, 2, 2, 3, 4, 5, 6, 7, 8]

>>>

C++实现:

#include

using namespace std;

void print (int st_bf[], size_t size){

for (size_t i = 0; i < size; i++)

{

cout<< st_bf[i] << " ";

}

cout<< endl;

}

void insert_sort(int st_bf[], size_t size){

// 插入排序代码

for (size_t i = 1; i < size; ++i)

{

int temp = st_bf[i];

int j = i - 1;

while (j >= 0 and st_bf[j] > temp)

{

st_bf[j+1] = st_bf[j];

j -= 1;

}

st_bf[j+1] = temp;

print(st_bf, size);

}

}

void shell_sort (int st_bf[], size_t size){

// 伪希尔排序代码

// k 为步长

for (size_t k = size/2; k > 1; k = k/2)

{

cout << "k = " << k << endl;

// i < k起分组哨兵的作用,否则重复比较 j< size避免越界

for (int i = 0, j = i+k; i < k and j < size; ++i, ++j)

{

for(int m = i, n = j; n < size; m += k, n += k)

{

cout << "i = " << m << " , j = " << n << endl;

cout << st_bf[m] << " " << st_bf[n] << endl;

if (st_bf[m] > st_bf[n])

{

int temp = st_bf[n];

st_bf[n] = st_bf[m];

st_bf[m] = temp;

}

}

}

print(st_bf, size);

}

// n = 1 普通插入排序

cout << "k = 1" << endl;

insert_sort(st_bf, size);

}

void shellsort(int *st_bf, size_t size)

// 真正的希尔排序

{

for (size_t k = size/2; k >= 1; k = k/2)

{

cout << "k = " << k << endl;

for (int i = k; i < size; ++i)

{

int temp = st_bf[i];

int j = i - k;

while (j >= 0 and st_bf[j] > temp)

{

st_bf[j+k] = st_bf[j];

j -= k;

}

st_bf[j+k] = temp;

}

print(st_bf, size);

}

}

int main(){

int st_bf[] = {6, 5, 3, 1, 8, 7, 2, 4, 2};

size_t size = sizeof(st_bf)/sizeof(st_bf[0]);

insert_sort(st_bf, size);

cout << "==========="<< endl;

int st_bf1[] = {6, 5, 3, 1, 8, 7, 2, 4, 2};

size = sizeof(st_bf1)/sizeof(st_bf1[0]);

shell_sort(st_bf1, size);

cout << "==========="<< endl;

int st_bf2[] = {6, 5, 3, 1, 8, 7, 2, 4, 2};

shellsort(st_bf2, size);

return 0;

}

结果同上。

参考资料

本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原创。还有未涉及的,会不定期更新,有错误请指正。

如果你看到这篇博文时发现不完整,那是我为防止爬虫先发布一半的原因,请看原作者Blog。

如果这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!如果您一定要转载,请带上后缀和本文地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值