算法理论——桶排序、计数排序、基数排序

简介: 桶排序、计数排序、基数排序这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:

概论

桶排序、计数排序、基数排序这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:

基数排序:根据键值的每位数字来分配桶;

计数排序:每个桶只存储单一键值;

桶排序:每个桶存储一定范围的数值;

实现

一、基数排序

概念

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

动态演示图如下:

2345_image_file_copy_52.jpg

代码

def RadixSort(a):
    max_len = len(str(max(a)))
    new = [0] * len(a)
    for i in range(max_len):
        print(new)
        x = 10 ** i
        index = [0]*10
        for w in range(len(a)):
            index[a[w] // x % 10] += 1
        for k in range(1, len(index)):
            index[k] = index[k] + index[k - 1]
        for j in range(len(a) - 1, -1, -1):
            new[index[(a[j] // x % 10)]-1] = a[j]
            index[(a[j] // x % 10)] -= 1
        a = copy(new)
        print(new)

二、计数排序

概念

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。

通俗地理解,例如有 10 个年龄不同的人,统计出有 8 个人的年龄比 A 小,那 A 的年龄就排在第 9 位,用这个方法可以得到其他每个人的位置,也就排好了序。当然,年龄有重复时需要特殊处理(保证稳定性),这就是为什么最后要反向填充目标数组,以及将每个数字的统计减去 1 的原因。

算法的步骤如下:

(1)找出待排序的数组中最大和最小的元素

(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项

(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

动态演示如下:

2345_image_file_copy_54.jpg

代码

def StackedCountSort(a):
    b = min(a)
    index = [0] * (max(a) - min(a) + 1)
    new = [0] * len(a)
    for i in range(len(a)):
        index[a[i] - b] += 1
    for x in range(1, len(index)):
        index[x] = index[x] + index[x - 1]
    for j in range(len(a) - 1, -1, -1):
        new[index[a[j]-b]-1] = a[j]
        index[a[j] - b] -= 1
    print(new)

三、桶排序

概念

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:

1.在额外空间充足的情况下,尽量增大桶的数量

2.使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中,同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。

代码

def bucket_sort_simplify(arr, max_num):
    """
    简化版
    """
    buf = {i: [] for i in range(int(max_num)+1)}  # 不能使用[[]]*(max+1),这样新建的空间中各个[]是共享内存的
    arr_len = len(arr)
    for i in range(arr_len):
        num = arr[i]
        buf[int(num)].append(num)  # 将相应范围内的数据加入到[]中
    arr = []
    for i in range(len(buf)):
        if buf[i]:
            arr.extend(sorted(buf[i]))  # 这里还需要对一个范围内的数据进行排序,然后再进行输出
    return arr
目录
相关文章
|
2月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
34 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
6月前
|
算法 搜索推荐
数据结构算法--6 希尔排序和计数排序
**希尔排序**是插入排序的改进版,通过分组插入来提高效率。它逐步减少元素间的间隔(增量序列),每次对每个间隔内的元素进行插入排序,最终增量为1时进行最后一次直接插入排序,实现整体接近有序到完全有序的过程。例如,对数组`5, 7, 4, 6, 3, 1, 2, 9, 8`,先以间隔`d=4`排序,然后`d=2`,最后`d=1`,完成排序。计数排序则适用于0到100的数值,通过统计每个数出现次数,创建对应计数数组,再根据计数重建有序数组,时间复杂度为`O(n)`。
|
2月前
|
搜索推荐 Java Go
深入了解计数排序算法
深入了解计数排序算法
41 4
|
2月前
|
搜索推荐 Java Go
深入了解基数排序算法
深入了解基数排序算法
35 3
|
2月前
|
搜索推荐 Java Go
探究桶排序算法
探究桶排序算法
28 1
|
2月前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
18 0
|
4月前
|
存储 搜索推荐 算法
Python中的桶排序算法
总结而言,桶排序是一个非常高效的排序算法,尤其适用于数据分布均匀的情况。正确实现和使用桶排序可以在特定情况下获得极高的排序速度。
25 0
|
5月前
|
算法 搜索推荐 C#
|
5月前
|
算法 搜索推荐 C#
|
5月前
|
存储 算法 搜索推荐