算法学习-02(希尔排序,计数排序,桶排序,基数排序)

yuanran0 2019-12-01

希尔排序

# 希尔排序
# 希尔排序是对插入排序的升级改造
# 它的大致流程是
# 1、将长度为n的序列 分为d = n//2组
# 2、使每一组变的有序
# 3、将序列分为 d1 = d // 2 组
# 4、将每一组变的有序
# 5、直到最后 d 小于等于 0

def inster_sort_gap(li,gap):
    for i in range(gap,len(li)):
        tmp = li[i]
        j = i - gap
        while j >= 0 and tmp > li[j]:
            li[j+gap] = li[j]
            j -= gap
        li[j+gap] = tmp

def shell_sort(li):
    n = len(li)
    gap = n // 2
    while gap > 0:
        inster_sort_gap(li,gap)
        gap //= 2

计数排序

#计数排序
    对列表进行排序,已知列表中的数范围都在0到100之间。
    设计时间复杂度为O(n)的算法
#eg:
    1 3 2 4 1 2 3 1 3 5
# 分配0-5六个桶,遇到一个数,在相应的桶上加一
0
1 1+1+1
2 1+1
3 1+1+1
4 1
5 1

复杂度 O(n)
占用空间 O(n)

# 计数排序
def count_sort(li, max_count):
    count = [0 for _ in range(max_count+1)]
    for i in li:
        count[i] += 1
    li.clear()
    for ind, val in enumerate(li):
        for i in range(val):

桶排序

# 如果计数排序中,如果元素的范围比较大(比如在1到1亿之间),如何改造算法

# 桶排序(Bucket Sort):
    把元素放在不同的桶里,对每个桶里面的元素保持有序

def bucket_sort(li,n=100,max_num=10000):
    """
    :param li: 需要排序的列表
    :param n: 分多少个桶
    :param max_num: 最大数
    :return:
    """
    buckets = [[] for _ in range(n)]
    for var in li:
        i = min(var // (max_num // n), n-1)  # i 表示var放到几号桶里面
        buckets[i].append(var)  # 把var 放到对应的桶里
        # 保持桶内的顺序
        for j in range(len(buckets[i])-1, 0, -1):
            if buckets[i][j] < buckets[i][j-1]:
                buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j]
            else:
                break
    sorted_li = []
    for buc in buckets:
        sorted_li.extend(buc)
    return sorted_li# 范围特别大,用的不是太多
# 桶排序的效率
# 取决于数据的分布,也就是需要对不同数据排序时,采取不同的分桶策略
    # 平均分布---
    # 不平均,90%的数在某一个桶里
    #
# 平均情况时间复杂度:O(n+k)
# 最坏情况时间复杂度:O(n**2k)
# 空间复杂度:O(nk)
# 还可以优化,比如内部排序过程

基数排序

# 先行知识点: 基于多关键字排序
    eg:对员工表进行薪资排序,薪资相同的按照年龄排序
          先按照年龄进行排序,再按照薪资进行稳定的排序

#对 32,13,19,52,54,94,3,17 的排序,也可以看作是多关键字排序
#先对个位数进行桶排序,再对十位数进行桶排序

时间复杂度,O(kn)
空间复杂度,O(k+n)
k表示数字位数

快排 nlogn  # logn=log(2,n)
计数排序 kn  # k=log(10,n)

当长度是固定的,数值范围越来越大,达到一定程度100000000...,基数排序的性能会变差

缺陷在于,需要占用空间

字符串的排序
# abcd
# ab00  #在面加0

数字排序,是在前面001 ,012,123

小数?

# 基数排序
def radix_sort(li):
    max_num = max(li)  # 取出最大值,99->2, 888->3, 10000->5
    it = 0  # 7--> it=0  77-->it=2, it等于0的时候,取个位数,it=1的时候,取的是十位数
    while 10 ** it <= max_num:          # 在每次里面进行分桶
        buckets = [[] for _ in range(10)]  # 0-9 共计 10个 桶
        for var in li:
            # 分到几号桶,看的是哪一位的数
            # 怎么取出对应位置上的数字
            # 987 it=0 取第一位7 987%10=7
            #     it=1 取第二位8 987//10=98 98%10=8
            #     it=2 取第三位9 987//100=9 9%10=9
            # 所以,公式: (987//10**it) % 10
            digit = (var // 10 ** it) % 10
            buckets[digit].append(var)
        # 已经做好了分桶
        # 把数重新写进li
        li.clear()
        for buc in buckets:
            li.extend(buc)
        it += 1

相关推荐