排序算法分析【二】:希尔排序(附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 <iostream>
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。

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

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

时间: 2024-08-01 01:16:10

排序算法分析【二】:希尔排序(附Python&C++代码)的相关文章

排序算法分析【一】:插入排序(附Python&amp;C++代码)

本文除了代码是自己写的,其余部分都是已存在内容.作者只是整理归纳学习,肯定不是原创,但是不是翻译,更不是转载,所以只能标注为原创,因为代码是原创.向前辈敬礼! 一.基本概念 排序算法(Sorting algorithm):将一串数据依照特定排序方式进行排列的一种算法. 排序算法是基础中的基础,重中之重.是某些算法如搜索算法.合并算法的前置算法.排序不仅仅是对数值排序,也可以是字符串. 排序算法的要求: 1.输出结果为递增(和需要排序的目标相同): 2.输出为输入的重新排列: 相关概念:[摘自百度

排序算法分析【五】:归并排序(附Python&amp;C++代码)

归并排序:将两个已经排序的串行合并成一个串行的操作. 算法原理 先看动态图: 算法描述如下: 申请空间,使其大小为两个已经排序串行之和,该空间用来存放合并后的串行: 设定两个指针,最初位置分别为两个已经排序串行的起始位置: 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置: 重复步骤3直到某一指针到达串行尾: 将另一串行剩下的所有元素直接复制到合并串行尾. 算法实现 Python版: #-*- encoding: utf-8 -*- def merge_sort(l

排序算法分析【四】:冒泡排序(附Python&amp;C++代码)

基本原理 冒泡排序(Bubble Sort,台湾另外一种译名为:泡沫排序)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 这样说还不是很明白,先看张图: 算法步骤: 1)比较相邻的元素.如果第一个比第二个大,就交换他们两个: 2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.

排序算法分析【三】:选择排序(附Python&amp;C++代码)

原理 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾.以此类推,直到所有元素均排序完毕. 选择排序的主要优点与数据移动有关.如果某个元素位于正确的最终位置上,则它不会被移动.选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换.在所有的完全依靠交换去移动元素

我的Java开发学习之旅------&gt;Java经典排序算法之希尔排序

一.希尔排序(Shell Sort) 希尔排序(Shell Sort)是一种插入排序算法,因D.L.Shell于1959年提出而得名.Shell排序又称作缩小增量排序. 二.希尔排序的基本思想 希尔排序的中心思想就是:将数据进行分组,然后对每一组数据进行排序,在每一组数据都有序之后 ,就可以对所有的分组利用插入排序进行最后一次排序.这样可以显著减少交换的次数,以达到加快排序速度的目的.       希尔排序的中心思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组.所有距离

算法学习之排序算法:希尔排序

希尔排序又称"缩小增量排序",它的基本思想是:先将整个待排记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对记录进行一次直接插入排序. 希尔排序的一个特点是:子序列的构成不是简单地"逐段分割",而是将相隔某个"增量"的记录组成一个子序列.这就使得希尔排序中关键字较小的记录不是一步一步地往前挪动,而是一次按照"增量"的大小跳跃式地往前移,从而使得在进行最后一趟增量为1的插入排

排序算法之希尔排序

文章转载自http://www.cnblogs.com/chengxiao/ 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现. 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组

SDUT 3403 数据结构实验之排序六:希尔排序

数据结构实验之排序六:希尔排序 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 我们已经学习了各种排序方法,知道在不同的情况下要选择不同的排序算法,以期达到最好的排序效率:对于待排序数据来说,若数据基本有序且记录较少时, 直接插入排序的效率是非常好的,希尔排序就是针对一组基本有序的少量数据记录进行排序的高效算法.你的任务是对于给定的数据进行希尔排序,其中增量dk=n/(2^k)(k=1,2

13. 蛤蟆的数据结构进阶十三排序实现之希尔排序法

13. 蛤蟆的数据结构进阶十三排序实现之希尔排序法 本篇名言:"一个人光溜溜的到这个世界来 ,最后光溜溜的离开这个世界而去 , 彻底想起来 , 名利都是身外物 ,只有尽一人的心力 , 使社会上的人多得他工作的裨益 ,是人生最愉快的事情.--邹韬奋" 下面是希尔排序法了. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47706135 1.  希尔排序 希尔排序(ShellSort)是插入排序的一种.也称缩小增量排序