希尔排序 计数排序 基数排序

希尔排序

  • 希尔排序思路
    • 希尔排序是一种分组插入排序算法。
    • 首先取一个整数d1=n/2,将元素分为d1个组,每组相邻量元素之间距离为d1,在各组内进行直接插入排序;
    • 取第二个整数d2=d1/2,重复上述分组排序过程,直到di=1,即所有元素在同一组内进行直接插入排序。
    • 希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序。
# 需要将 插入排序的所有的 1 改成 d
# 用到的插入排序
def insert_sort(li, d):
    for i in range(d,len(li)):
        tmp = li[i]
        j = i-d
        while j>=0 and li[j]>tmp:
            li[j+d] = li[j]
            j-=d
        li[j+d] = tmp

def shell_sort(li):
    d = len(li) // 2
    while d > 0:
        insert_sort(li,d)
        d = d // 2
        
li = list(range(100000))
random.shuffle(li)
shell_sort(li)
print(li)

计数排序

  • 现在有一个列表,已知列表中的数范围都在0到100之间。设计算法在O(n)时间复杂度内将列表进行排序。
  • o创建一个列表,用来统计每个数出现的次数。
import random
from cal_time import cal_time

@cal_time
def count_sort(li, max_num=100):
    # 生成从 0 到 最大值的列表 
    count = [0 for _ in range(max_num+1)]
    for val in li:
        count[val] += 1
    li.clear()
    for a, b in enumerate(count):
        # li.extend([a]*b)
        for j in range(b):
            li.append(a)


@cal_time
def sys_sort(li):
    li.sort()


li = [random.randint(0,100) for _ in range(100000)]
count_sort(li)

桶排序

  • 在计数排序中,如果元素的范围比较大(比如在1到1亿之间),如何改造算法?
  • 桶排序(Bucket Sort):首先将元素分在不同的桶中,在对每个桶中的元素排序。
  • 桶排序的表现取决于数据的分布。也就是需要对不同数据排序时采取不同的分桶策略。
  • 平均情况时间复杂度:O(n+k)
  • 最坏情况时间复杂度:O(n 2 k)
  • 空间复杂度:O(n k)

基数排序

  • 多关键字排序:加入现在有一个员工表,要求按照薪资排序,年龄相同的员工按照年龄排序。
  • 先按照年龄进行排序,再按照薪资进行稳定的排序。
  • 对32,13,94,52,17,54,93排序,是否可以看做多关键字排序?
  • 就是按照 位数进行排序 i=0 个位 i=1 十位
  • 1,10,100,1000,10000.....
  • 时间复杂度: O(kn)
  • 空间复杂度: O(k+n) (k 表示数字位数)
import random
from cal_time import cal_time

# 多关键字排序 第一关键字、第二关键字、...
# 排序是稳定的

# li = [
#     {'sal':2000, 'age':18},
#     {'sal':5000, 'age':30},
#     {'sal':6000, 'age':30},
#     {'sal':5000, 'age':18},
#     {'sal':2000, 'age':30},
# ]

# li.sort(key=lambda x: (x['sal'], x['age']))

# li.sort(key=lambda x:x['age'])
# li.sort(key=lambda x:x['sal'])


# num = 56
# i = 2
# digit = num // 10**i % 10

@cal_time
def radix_sort(li):
    max_val = max(li)  # 先找出最大值
    i = 0  # 每次循环选取的 位数  第一次  个位

    while 10 ** i <= max_val:  # 循 环条件  位数的  不能大于最大的 值 1000 不能大于 999  没有千位
        count = [[] for _ in range(10)]  # 创建存储 的列表
        for val in li:
            dig = val // 10 ** i % 10  # 首次 选出 列表中所有 的个位基数  
            count[dig].append(val)   # 按基数的位置 放入 存储列表中
        li.clear()  # 清空之前的 列表
        # 重新 赋值列表
        for l in count:
            for val in l:
                li.append(val)
        i += 1  # 增加基数

#li = list(range(100000))
li = [random.randint(0,999) for _ in range(100000)]
random.shuffle(li)
radix_sort(li)

posted @ 2019-04-22 12:54  拐弯  阅读(273)  评论(0编辑  收藏  举报