排序算法第三篇--(计数排序、基数排序、桶排序)

一些非比较排序:计数排序,基数排序,桶排序

前面所讲述的算法皆为比较排序算法,在最坏情况下的最优排序效率为O(nlogn),如何超越比较排序的效率?在用比较进行排序的前提下,这个算法效率是无法超越的。

4.1 基于排序的规则
一个简单例子
‘’’
每一个排序关键字是1或者是2
的数组如何排序
‘’’
#思想:统计1出现的次数和2出现的次数
#假定为1出现的次数为k,择2出现的次数为n-k
#将填充到前k个位置,2填充到n-k的位置

A=[1,2,1,1,1,2,2]
def simple_sort(A):
    n=len(A)
    k=0
    for i in range(n):
        #统计1的个数
        if A[i]==1:
            k+=1
    for i in range(k):
        #将前k个数设置为1
        A[i]=1
    for i in range(k,n):
        #将剩余n-k个数设置为2
        A[i]=2
simple_sort(A)
print(A)

‘’’
时间复杂度为O(n),该算法并不会对元素进行比较
‘’’

#4.2基于比较排序的下界

‘’’
可以证明,只要是比较排序,其最差情况下的效率下界是O(nlogn)

排序算法的通用下界为O(n),即至少需要对每个元素进行一次检查

‘’’

#4.3计数排序

‘’’

如果序列的排序关键字是(0~~m)范围内的正整数,可以使用计算排序
直接寻找关键应该放置的索引位置,而且无论有无卫星数据,
这种计数排序的时间复杂度都是O(n),
这种排序并不是原址排序
这种排序是稳定排序

‘’’

#计数程序:对数组中每个元素的个数进行统计
#(要求数组中的数据都是大于或等于0的正整数)
def count_key(A):
    """
    m:A中元素的取值范围(0~m)
    return:equal[0...m]  表示A中每个元素出现的次数       
    """
    m=max(A)
    #求数组中出现的最大元素
    n=len(A)
    equal=[0]*(m+1) 
    #可能存在的元素为(m+1)
    #统计每个元素出现次数的数组
    for i in range(0,n):
        key=A[i]
        equal[key]+=1
    return equal

A=[1,2,1,2,1,2]
B=count_key(A)
print(B)

#统计less[]数组,数组中第表示less[j]中存放了排序关键字小于j的元素个数

def count_key_less(equal):
    """
    equal:统计每个元素出现次数的数组
    m: m:A中元素的取值范围(0~m)

       return:输出:一个数组less[0..m]
           表示less[j]中存放了排序关键字小于j的元素个数: 
    """
    n=len(equal)
    less=[0]*n
    #less[0]=0
    for i in range(1,n):
        less[i]=less[i-1]+equal[i-1]
    return less

a=[0,3,3]
b=count_key_less(a)
print(b)


#计数排序函数

def  count_sort(A,less):
    """
    return 数组B,已经排好序

    """
    n=len(A)
    B=[0]*n
    next=[0]*n
    next=less 
    #不改变less数组

    for i in range(0,n):
        key=A[i]
        index=next[key]
        B[index]=key
        next[key]=next[key]+1

    return B
A=[1,2,1,2,1,2]
B=count_key(A)
less=count_key_less(B)
D=count_sort(A,less)
print(D)

#基数排序

‘’’
基数排序(Radix Sort)是一种非比较型整数排序算法
基本思想是:
将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
按照低位先排序,分别放入10个队列中,然后采用先进先出的原则进行收集;
再按照高位排序,然后再收集;
依次类推,直到最高位,
最终得到排好序的数列。
对于数值偏小的一组序列,其速度是非常快的,
时间复杂度达到了线性,而且思想也非常的巧妙。

‘’’
注意:一定要按照从低位到高位的顺序排序。

‘’’
伪代码:
1.取得数组中的最大数,并取得位数;
2.对数位较短的数前面补零;
3.分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中;
4.收集,再将放置在0~9号桶中的数据按顺序放到数组中;
5.重复3~4过程,直到最高位,即可完成排序。

‘’’


from typing import List
def radix_sort(arr:List[int]):
    n=len(str(max(arr)))
    #求最高位数字的位数
    for k in range(n):
        #从低到高n轮排序       
        bucket_list=[[] for _ in range(10)]
        #每一轮生成10个列表(因为数字为0~9,建立10个桶)
        for i in arr:
            #遍历数组元素
            bucket_list[i//(10**k)%10].append(i)
            #按照第k位放在桶中
        arr=[j for i in bucket_list for j in i]
        #按照当前桶的顺序重新排列数组
    return arr 
if __name__=="__main__": 
    import random 
    random.seed(54)
    arr=[random.randint(0,100) for _ in range(10)]
    print(arr)
    arr_new=radix_sort(arr)
    print(arr_new)

待完善:

???

1.桶排序和计数排序是一回事吗?

2.基数排序到底是基于桶排序还是基于计数排序的?

3.什么叫排序算法的稳定性?

桶排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值