排序 7 - 希尔排序

10 篇文章 0 订阅
10 篇文章 0 订阅

参考:

排序 0 - 前言

百度百科:希尔排序


希尔排序(shell sort)

工作原理

直接插入排序的改进,设置步长,对间隔步长大小的数据进行直接插入排序,不断减小步长,直至步长大小为 1。也称为缩小增量排序

算法思想

通常初次设置步长大小为 n/2,之后每次取步长大小的一半,每次均对序列进行遍历,对间隔步长大小的数据进行直接插入排序


Python 算法实现

# -*- coding: utf-8 -*-

"""
希尔排序实现
"""

import random
import math

__author__ = 'zj'


def create_data(leng, min, max):
    """
    创建待排序序列
    :param leng: 序列长度
    :param min: 最小值
    :param max: 最大值
    :return: 列表
    """
    li = range(min, max)
    return random.sample(li, leng)


def shell_sort(li, reverse=False):
    """
    希尔排序实现
    :param li: 待排序列表
    :param reverse: 是否从大到小排序,默认为False
    :return: 已排序列表
    """
    step = int(math.ceil(len(li) / 2))
    while step > 0:
        for i in xrange(step):
            idx_list = [x for x in xrange(len(li)) if (x - i) % step == 0]  # 获取间隔为 d 的下标
            for j in xrange(1, len(idx_list)):  # 遍历同一组子序列
                for k in xrange(j):
                    if reverse:
                        if li[idx_list[k]] < li[idx_list[j]]:
                            li[idx_list[k]], li[idx_list[j]] = li[idx_list[j]], li[idx_list[k]]
                    else:
                        if li[idx_list[k]] > li[idx_list[j]]:
                            li[idx_list[k]], li[idx_list[j]] = li[idx_list[j]], li[idx_list[k]]
        if step == 1:
            step = 0
        else:
            step = int(math.ceil(step / 2))
    return li


if __name__ == '__main__':
    da = create_data(10, 30, 60)
    print da
    shell_sort(da, True)
    print da

性能分析

稳定性

希尔排序是不稳定排序算法

由于每次遍历时,只对间隔步长大小的数据进行直接插入排序,所以可能导致相同大小数据的相对位置发生变化

比如,待排序序列为 (4,0)(3,1)(4,2)(2,3)(2,4)

  • 首次设置步长为 3,那么子序列为 (4,0)(2,3)(3,1)(2,4)(4,2)

排序结果为 (2,3)(2,4)(4,2)(4,0)(3,1)

  • 第二次设置步长为 1,那么直接对整个序列进行插入排序

排序结果为 (2,3)(2,4)(3,1)(4,2)(4,0)

由结果可知,值为 4 的数据的相对位置发生了变化

时间复杂度

网上找了比较多的希尔排序的时间分析,没有一个统一的意见

最坏时间复杂度为 O(n*log2n)

平均时间复杂度均为 O(n^1.5)

空间复杂度

空间复杂度为 O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值