• 详解计数排序


    相较于冒泡排序,快速排序他们之间都是基于元素之间的比较来进行排序的。
    而计数排序可以做到线性的时间复杂度,是由于它是利用数组下标来确定元素的正确位置的。
    那么如何利用数组下标来确定元素位置呢?
    给定一个20个整数的无序数列,取值范围是0-10,所以就可以创建一个长度为11的数组。然后开始遍历这个无序的随机数列,每一整数按照其值对号入座,这时在这个创建的数组上对应其值的下标的元素加1.
    有点绕,就是假设20个整数中有3个9,那么我们就找到那3个9,并在对应数组的索引的元素上加1.所以创建的数组元素的索引9上的元素是3。
    最终,当这个无序数列遍历完毕之后,该数组中每一个下标位置的值代表数列中对应整数出现的次数。
    有了这个统计就可以直接遍历数组,输出数组下标的值(索引),元素的值是几,就输出几次。
    这里需要编写的操作主要有

    1.确定数组的长度

    max_value = array[0]
        for i in range(1, len(array)):
            if array[i] > max_value:
                max_value = array[i]
    

    先假设列表中第一个元素最大,然后遍历列表,比较找出最大的那个值
    然后根据这个值创建数组

    count_array = [0] * (max_value+1)
    

    2.遍历数列,填充统计数组(这也是最重要的一步)

        for i in range(0, len(array)):
            count_array[array[i]] += 1 
    

    这里用数列的值当做索引,然后再加1.若一个数列中相同的值很多,那么就会继续加1

    3.遍历统计数组,输出结果

    sorted_array = []
        for i in range(0, len(count_array)):
            for j in range(0, count_array[i]):
                sorted_array.append(i)
        return sorted_array
    

    这里创建个数组来接收排序后的列表,利用count_array[i]这个代表无序数列中具体的元素有几个来进行for循环。可以精确的输出元素有几个。

    这样输出该数组就达到了计数排序的目的了

    但这里还有些优化的点。比如,
    1.我们无法确定输出相同值元素原本在无序数列中的顺序,这就造成这是个不稳定排序
    2.创建数组的长度是根据无序数列中最大元素确定的,这个其实是不可取的。如:99,100,22,33,4,5.这6个元素组成的无序数列,按最大元素就要创建100个下标的数组,这太浪费空间了。
    对于第1点优化的点可以采用从统计数组的第二个元素开始,每个元素都加上前面所有元素之和。
    对于第2点优化可以采用max_value-min_value+1得出数组的长度,但这其实还是比较浪费空间(这里其实可以去看看堆排序,他在创建数组空间上做的比较好)

    完整代码(优化的计数排序)

    # 计数排序的优化属于稳定版本的计数排序,可以返回相同数据的顺序先后;可用在学生成绩排名
    def count_sort_v2(array=[]):
        # 1.得到数列的最大值最小值,并算出差值d
        max_value = array[0]
        min_value = array[0]
        for i in range(1, len(array)):
            if array[i] > max_value:
                max_value = array[i]
            if array[i] < min_value:
                min_value = array[i]
        d = max_value - min_value
        # 2.创建统计数组并统计对应元素个数
        count_array = [0] * (d+1)
        for i in range(0, len(array)):
            count_array[array[i]-min_value] += 1 # 这里创建的统计数组全为0
        # 3.统计数组做变形,后面的元素等于前面的元素之和
        for i in range(1, len(count_array)):
            count_array[i] += count_array[i-1] # 这算个列表的技巧,后面索引的值是前面索引值的和
        # 4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组
        sorted_array = [0] * len(array)
        for i in range(len(array)-1, -1, -1): # array[i]是原数组的值
            # 这里减1是为啥,因为数组是从0开始的
            sorted_array[count_array[array[i]-min_value]-1] = array[i] # count_array[array[i]-min_value]填充统计数组的值,min_value是统计数组的开头
            count_array[array[i] - min_value] -= 1
        return sorted_array # 返回的是重新创建的数组,这里创建了2个数组
    
    
    my_array = list([4, 4, 6, 5, 3, 2, 8, 1, 7, 5, 6, 0, 10])
    print(count_sort(my_array))
    my_array = list([95, 94, 91, 120, 90, 99, 93, 91, 92])
    print(count_sort_v2(my_array))
    
    
    努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
  • 相关阅读:
    字符串前面加@
    SQL字段类型bit 查询时注意
    SELECT IDENT_CURRENT(tableName)和自增长列的纠结
    解析xml文件 selectSingleNode取不到节点
    【.NET】.NET MVC4 微信扫一扫功能实现附全部代码
    未定义对象
    C# Web开发中弹出对话框的函数[转载]
    json序列化和反序列化
    jq的$.each()方法
    学习URLRewriter.dll的使用
  • 原文地址:https://www.cnblogs.com/wkhzwmr/p/15344768.html
Copyright © 2020-2023  润新知