Python数据结构与算法 算法基础(番外2)——算法基础完结

计数排序:

        前提是要知道待排序的数中最大值与最小值

        计数数组中,下标表示待排序的数,而值表示该数的个数

        在开始计数排序之前,先通过一段代码了解一下enumerate函数的作用

s = [1, 2, 3, 3, 4] # 假设这是计数算法得到的tli,表示有1个0;  2个1...
li = []
for ind, val in enumerate(s):
    print(ind, val)
    for i in range(val) :
        li.append(ind)
print(li)
0 1
1 2
2 3
3 3
4 4
[0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4]

        通过代码与结果可以看出,enumerate是读取列表中的坐标与值

以下是计数排序的代码实现:

def count_sort(li, max_num = 100) :
    tli = [0 for _ in  range(max_num + 1)]  # 创建一个用于记录的列表
    for i in li :
        tli[i] += 1
    li.clear()
    for ind, val in enumerate(tli) :
        for i in range(val) :
            li.append(ind)


import random
s = [random.randint(0, 100) for _ in range(200)]    # 创建一个值在0~100,大小为200的列表,保证有重复的数
print(s)
count_sort(s)
print("***************************************************************************")
print(s)
[16, 77, 31, 39, 18, 2, 47, 50, 63, 30, 49, 31, 19, 69, 88, 54, 72, 91, 20, 78, 40, 32, 36, 79, 8, 88, 30, 100, 70, 38, 1, 71, 99, 65, 61, 49, 23, 48, 60, 1, 36, 24, 20, 96, 63, 0, 73, 5, 41, 24, 33, 45, 7, 71, 96, 61, 53, 32, 50, 0, 45, 67, 87, 94, 53, 2, 72, 98, 23, 60, 64, 37, 38, 40, 21, 37, 37, 2, 95, 48, 65, 23, 95, 56, 92, 41, 8, 49, 40, 76, 35, 100, 36, 74, 35, 47, 49, 24, 100, 83, 57, 23, 1, 18, 39, 56, 76, 53, 70, 64, 73, 88, 54, 2, 53, 56, 33, 49, 79, 81, 65, 96, 68, 47, 13, 93, 65, 37, 61, 8, 50, 91, 64, 61, 80, 30, 29, 86, 0, 46, 4, 87, 71, 43, 39, 89, 26, 96, 97, 48, 66, 64, 82, 96, 11, 1, 36, 2, 64, 81, 84, 45, 74, 65, 18, 61, 12, 43, 18, 23, 53, 74, 94, 52, 74, 96, 82, 41, 96, 92, 96, 30, 85, 58, 59, 45, 48, 26, 90, 10, 34, 24, 53, 24, 72, 91, 56, 97, 6, 51]
***************************************************************************
[0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 4, 5, 6, 7, 8, 8, 8, 10, 11, 12, 13, 16, 18, 18, 18, 18, 19, 20, 20, 21, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 26, 26, 29, 30, 30, 30, 30, 31, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 43, 43, 45, 45, 45, 45, 46, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 50, 50, 51, 52, 53, 53, 53, 53, 53, 53, 54, 54, 56, 56, 56, 56, 57, 58, 59, 60, 60, 61, 61, 61, 61, 61, 63, 63, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 67, 68, 69, 70, 70, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74, 74, 76, 76, 77, 78, 79, 79, 80, 81, 81, 82, 82, 83, 84, 85, 86, 87, 87, 88, 88, 88, 89, 90, 91, 91, 91, 92, 92, 93, 94, 94, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 98, 99, 100, 100, 100]

        计数算法的时间复杂度为O(n),是排序算法中最快的,但是条件比较苛刻:

                1、知道最大最小数;

                2、都是非负整数;

                3、如果待排序为[2, 1, 800, 13000, 20],则需要开辟大小为13000的空间作为tli

桶排序:

        桶排序可能不太实用,但是为下一个较为关键的排序所做的铺垫,所以主要理解其排序的思路即可。

        桶排序是将一组无序的数逐步降低其逆序数,实现排序,如已知待排序的数范围为1~10000,则将每一千个数看作一桶(组),各自桶内有序后,将各个桶拼接起来即可。

def bucket_sort(li, n = 100, max_num = 10000) :     # 将默认最大为max_num的数分到默认为n个桶里
    tli = [[] for _ in range(n)]   # 创建桶为一个二维列表,有n行,每一行为一个空列表
    l = max_num // n    # 每一桶有l个数
    for val in li :
        i = min(val // l, n - 1)    # i表示放进第几号桶里,n - 1 表示最后一个桶,若max_num = 10000 ,n - 1用于存储该数
        tli[i].append(val)
        for j in range(len(tli[i]) - 1, 0, -1) :    # 保证桶内数字有序
            if tli[i][j] < tli[i][j - 1] :
                tli[i][j], tli[i][j - 1] = tli[i][j - 1], tli[i][j]
    sorted_list = []
    count = 0
    for i in tli :
        print(count)
        count += 1
        print(i)
        sorted_list.extend(i)
    return sorted_list
import random
s = list(random.randint(0, 100) for i in range(150))    # s长度为150,随机数范围在0~100,保证有重复
print(s)
print(bucket_sort(s, 10, 100))
[29, 47, 74, 31, 34, 60, 0, 96, 12, 35, 84, 44, 72, 91, 88, 86, 59, 21, 76, 21, 91, 85, 78, 19, 84, 2, 42, 45, 68, 6, 69, 82, 22, 94, 19, 86, 81, 61, 83, 8, 32, 62, 61, 9, 20, 29, 85, 76, 5, 88, 84, 69, 13, 34, 49, 91, 20, 72, 39, 39, 50, 19, 20, 95, 67, 29, 96, 61, 52, 30, 16, 11, 67, 48, 43, 21, 36, 74, 4, 78, 25, 9, 8, 97, 27, 67, 54, 54, 9, 82, 54, 7, 58, 84, 71, 11, 64, 92, 76, 38, 82, 18, 8, 75, 14, 91, 66, 1, 54, 29, 64, 7, 57, 8, 89, 40, 40, 43, 14, 100, 33, 37, 13, 91, 71, 11, 74, 66, 92, 67, 20, 15, 100, 5, 90, 7, 26, 77, 92, 70, 11, 77, 20, 22, 57, 79, 35, 40, 7, 92]
0
[0, 1, 2, 4, 5, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9]
1
[11, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 18, 19, 19, 19]
2
[20, 20, 20, 20, 20, 21, 21, 21, 22, 22, 25, 26, 27, 29, 29, 29, 29]
3
[30, 31, 32, 33, 34, 34, 35, 35, 36, 37, 38, 39, 39]
4
[40, 40, 40, 42, 43, 43, 44, 45, 47, 48, 49]
5
[50, 52, 54, 54, 54, 54, 57, 57, 58, 59]
6
[60, 61, 61, 61, 62, 64, 64, 66, 66, 67, 67, 67, 67, 68, 69, 69]
7
[70, 71, 71, 72, 72, 74, 74, 74, 75, 76, 76, 76, 77, 77, 78, 78, 79]
8
[81, 82, 82, 82, 83, 84, 84, 84, 84, 85, 85, 86, 86, 88, 88, 89]
9
[90, 91, 91, 91, 91, 91, 92, 92, 92, 92, 94, 95, 96, 96, 97, 100, 100]
[0, 1, 2, 4, 5, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 11, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 18, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 22, 22, 25, 26, 27, 29, 29, 29, 29, 30, 31, 32, 33, 34, 34, 35, 35, 36, 37, 38, 39, 39, 40, 40, 40, 42, 43, 43, 44, 45, 47, 48, 49, 50, 52, 54, 54, 54, 54, 57, 57, 58, 59, 60, 61, 61, 61, 62, 64, 64, 66, 66, 67, 67, 67, 67, 68, 69, 69, 70, 71, 71, 72, 72, 74, 74, 74, 75, 76, 76, 76, 77, 77, 78, 78, 79, 81, 82, 82, 82, 83, 84, 84, 84, 84, 85, 85, 86, 86, 88, 88, 89, 90, 91, 91, 91, 91, 91, 92, 92, 92, 92, 94, 95, 96, 96, 97, 100, 100]

基数排序:

       当有多个关键字时,比如某公司按照薪资排序,薪资相同时,按照年龄排序:此时先按照年龄排序,再按照薪资进行稳定排序,即薪资相同时,不改变事先的年龄排序,也就是先将第二关键字排序,再对第一关键字进行稳定排序。

        如果应用到数字上,对于两位数,可以先对个位数进行桶排序,然后输出,再对十位数进行桶排序,输出后,便已完成排序任务。因为对个位数的桶排序保证了对十位数进行桶排序时,个位数小的会先进入桶中,比如s = [12, 17, 15, 23, 22]进行排序时,按照个位数进行桶排序后输出为[12, 22, 23, 15, 17] 这样从s[0]到s[4],对十位桶排序时,12一定比15先进入桶中,实现排序。

        因为在比较大小时,先看十位数,再看个位数,类比上文先比较薪资再比较年龄,个位数为第二关键字,十位数为第一关键字。

        用代码实现:

def radix_sort(li) :
    max_num = max(li)
    it = 0
    while 10 ** it <= max_num :     # it记录当前位数,it = 0时为个位
        tli = [[] for _ in range(10)]
        for val in li :     # 按照当前位数进行分桶,如
            i = (val // 10 ** it) % 10  # it = 1 ;val = 213; i = (213 // 10) % 10 = 1即按十位分桶
            tli[i].append(val)
        # 完成了一次桶排序
        li.clear()
        for t in tli :
            li.extend(t)
        it += 1
import random
s = list(random.randint(0, 1314) for i in range(50))
print(s)
radix_sort(s)
print(s)
[1190, 1066, 1224, 303, 312, 866, 6, 617, 462, 376, 236, 1084, 973, 904, 687, 854, 323, 1072, 655, 1198, 1087, 560, 494, 1089, 46, 735, 234, 130, 1172, 1007, 1260, 420, 916, 1051, 1026, 391, 1002, 367, 728, 361, 43, 1064, 488, 546, 1087, 742, 1123, 524, 806, 710]
[6, 43, 46, 130, 234, 236, 303, 312, 323, 361, 367, 376, 391, 420, 462, 488, 494, 524, 546, 560, 617, 655, 687, 710, 728, 735, 742, 806, 854, 866, 904, 916, 973, 1002, 1007, 1026, 1051, 1064, 1066, 1072, 1084, 1087, 1087, 1089, 1123, 1172, 1190, 1198, 1224, 1260]

        基数排序的时间复杂度为O(kn), 其中k为指数,在每层中为n;空间复杂度为O(k + n)

        截止至本篇,算法基础的知识部分已完结。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值