希尔排序、计数排序、桶排序、基数排序

希尔排序

希尔排序思路:

  • 希尔排序是一种分组插入排序算法。
  • 首先取一个整数d1=n/2, 将元素分为d1个组, 每组相邻量元素之间距离为d1,在各组内进行直接插入排序
  • 取第二个整数d2=d1/2, 重复上述分组排序过程,直到di=1,即全部元素在同一组内进行直接插入排序
  • 希尔排序每趟并不使某些元素有序,而是使总体数据愈来愈接近有序;最后一趟排序是的全部数据有序。
  •  

 

复习一下插入排序:git

def insert_sort(li): for i in range(1, len(li)): j = i - 1 # j 为手里最大的牌      tmp = li[i] while j >= 0 and li[j] > tmp: # 只要手里最大的牌比摸回来的牌大就一致往右移动 # j >= 0 ,说明全部数都比摸到的牌要大,直接退出循环 li[j+1] = li[j] # 右移 j -= 1 li[j+1] = tmp     # 肯定要插入的时候,是必须插到j的前一个位置

再看实现希尔排序代码:

def insert_sort(li, gap): for i in range(gap, len(li)): j = i - gap tmp = li[i] # 摸回来的牌的值 while j >= 0 and li[j] > tmp: # 在有序区里面,摸回来的牌比有序区的牌(从右到左)的值小,有序区的牌就向右移动一个位置 li[j+gap] = li[j] j -= gap li[j+gap] = tmp def shell_sort(li): d = len(li) // 2
    while d >= 1: insert_sort(li, d) d = d // 2
 li = list(range(1000)) import random random.shuffle(li) shell_sort(li) print(li)

希尔排序小结:

  希尔排序的时间复杂度比较复杂,且和选区的grap序列有关。算法

 

计数排序

如今有一个列表,已知列表中的数范围都在0到100之间。设计算法在O(n)时间复杂度内将列表进行排序。shell

思路:

建立一个列表,用来统计每一个数出现的次数。(index存数字大小,value存出现次数)app

def count_sort(li, max_num): # 建立一个max_num长的列表 count = [0 for i in range(max_num + 1)] for num in li: count[num] += 1 li.clear() for ind, val in enumerate(count): for i in range(val): li.append(ind) import random li = [random.randint(0,100) for _ in range(1000)] count_sort(li, len(li)) print(li)

计数排序的缺点:dom

若是列表只有5个数,数字范围是1到1亿,就须要开一个一亿长度的列表,严重浪费空间和资源不合理使用。spa

 

桶排序

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

桶排序(Bucket Sort):首先将元素分在不一样的桶中,再对每一个桶中元素排序。code

  • 桶排序的表现取决于数据的分布。也就是须要对不一样数据排序时采起不一样的分桶策略。
  • 平均状况时间复杂度:O(n+k)
  • 最坏状况时间复杂度:O(n2k)
  • 空间复杂度:O(nk)

 

def bucket_sort(li, n=100, max_num=10000): buckets = [[] for i 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]:     # 必须是升序   降序的话[9,8,7,6] [99,87,55,22], 合并以后并非有序 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 import random li = [random.randint(0,99999) for i in range(100)] li = bucket_sort(li) print(li)

 

基数排序

基数排序是按照低位先排序,而后收集;再按照高位排序,而后再收集;依次类推,直到最高位。blog

 

 

def radix_sort(li): max_num = max(li) # 最大值 9->1, 99->2, 888->3, 10000->5 it = 0
    while 10 ** it <= max_num: buckets = [[] for _ in range(10)] for var in li: # 987 it=1  987//10->98 98%10->8; it=2 987//100->9 9%10=9
            digit = (var // 10 ** it) % 10
            buckets[digit].append(var) # 分桶完成 li.clear() for buc in buckets: li.extend(buc) # 把数从新写回li it += 1