桶排序python实现(超详细讲解)适用0基础强化版

本文介绍了桶排序的原理,包括如何将数据分配到有限数量的桶中进行排序,以及其在理想和最坏情况下的时间复杂度分析。同时,详细讲解了空间复杂度和选择排序在桶排序中的应用。
摘要由CSDN通过智能技术生成

桶排序是什么?

        桶排序(Bucket Sort)的主要思想是:桶排序的思想是将待排序数据分配到有限数量的桶中,每个桶中的数据再单独进行排序。通过合理设置桶的容量和数量,使得数据能够均匀分布,从而提高排序效率。最后,将各个桶中已排序的数据依次合并,得到完整的排序结果。

 桶排序的性能如何?

时间复杂度:

        在理想情况下,当数据均匀分布在各个桶中,并且每个桶内的排序算法时间复杂度较低时,桶排序的总体时间复杂度可以达到O(n),其中n为待排序元素的数量。这是因为每个桶内的排序可以独立进行,且桶的数量通常远小于n,所以总体时间复杂度接近于线性。

        在最坏情况下,如果所有数据都分布在一个桶中,桶排序的时间复杂度可能会达到O(n^2),类似于插入排序或冒泡排序的性能。

空间复杂度:

        桶排序通常需要额外的空间来存储桶本身以及桶内元素。因此,空间复杂度至少为O(n+k),其中k为桶的数量。如果桶的数量较大或者桶内元素需要额外的空间进行排序,则空间复杂度会进一步增加。

以下是代码(含有注释):

def selection_sort(arr): #选择排序
    for i in range(len(arr)): #遍历原数组
        min_index=i #假设最开始的最小值的下标为i,实际上最小值下标后面遍历后会更改
        for j in range(i+1,len(arr)):   #找出最小值的下标min_index
            if arr[j]<arr[min_index]:   #如果有比找到的最小值更小的数
                min_index=j             #就更新最小值的下标
    #最重要的是,找到最小值要交换。目的让每一次最小的数在最左边。
        arr[i],arr[min_index]=arr[min_index],arr[i]
def Bucket_sort(arr):
    min_value=min(arr) #定义原数组最小值
    max_value=max(arr) #定义原数组最大值
    bucketcount=3 #桶的数量 !!! 注意,我们这里只是简单说明一个桶排序思想,并不一定固定桶的数量,当元素很多时,桶的数量会更多
    bucket=[[],[],[]] #记录不同桶的数据
    perBucket=(max_value -min_value+bucketcount)//bucketcount #计算每个桶不同数字的元素个数
    #这里的加bucket 是因为有不同的桶,要均匀的分配
    for num in arr:
        bucketindex=(num -min_value)//perBucket #选择一个合适的桶
        bucket[bucketindex].append(num) #把元素塞进桶里
    for i in range(bucketcount): #遍历每个桶
        selection_sort(bucket[i]) #每个桶进行选择排序 减小了数据规模
    idx=0 #下标,用于把每个桶里面的数据放回原列表
    for i in range(bucketcount): #遍历不同的桶
        for v in bucket[i]: # 遍历桶里面的数据
            arr[idx]=v #把数据给放原理的列表当中
            idx+=1 #遍历完当前元素后 往后走一个位置,继续遍历同一个桶里面的下一个元素

arr=[2,4,1,3,6,9,8,7]
Bucket_sort(arr) #在Bucket_sort里面包含了选择排序,所以只需要调用一个函数
print(arr)

如果你看不懂怎么办?

        不要慌,这里我会给出详解。我们先来看看步骤。

桶排序的基本步骤包括:

  1. 设置桶的容量和数量:根据待排序数据的范围和分布情况,确定桶的容量和桶的数量。桶的容量应该足够小,使得数据能够相对均匀地分配到各个桶中。

  2. 分配数据到桶中:遍历待排序的数据,根据每个数据的大小,将其分配到对应的桶中。通常,这一步会用到一个映射函数,将数据映射到相应的桶索引上。

  3. 对每个桶中的数据排序:在分配完数据后,每个桶中都会包含一部分数据。接下来,对每个桶中的数据进行排序。这里可以使用任何其他的排序算法,比如插入排序、快速排序等,根据具体情况选择。

  4. 合并桶中的数据:当每个桶中的数据都排序完成后,按照桶的顺序,将桶中的数据依次取出,合并成一个有序序列。

每段代码执行的任务:

一:

def selection_sort(arr):  
    for i in range(len(arr)):  
        min_index = i  
        for j in range(i+1, len(arr)):  
            if arr[j] < arr[min_index]:  
                min_index = j  
        arr[i], arr[min_index] = arr[min_index], arr[i]

这段代码(选择排序)的基本思想是:

  1. 遍历数组,从第一个元素开始,将其假设为当前最小值的下标。
  2. 继续遍历数组,如果找到更小的元素,则更新最小值的下标。
  3. 当内部循环结束后,我们已经找到了从当前位置到数组末尾的最小值下标。
  4. 将当前位置与找到的最小值交换位置。
  5. 重复上述步骤,直到整个数组排序完成。

二:

def Bucket_sort(arr):  
    min_value = min(arr)  
    max_value = max(arr)  
    bucketcount = 3  
    bucket = [[], [], []]  
    perBucket = (max_value - min_value + bucketcount) // bucketcount  
  1. 确定数组中的最小值和最大值。
  2. 定义桶的数量,数据更大的时候可能桶的数量更大,这里只是给出简单的数据3来说明桶排序的思想。
  3. 建立二维列表,用于存放每个桶的数据。
  4. 根据最小值和最大值,以及桶的数量,计算每个桶的范围(perBucket)。你是不是以为每个桶只需要(最大值-最小值)//桶的数量,就够了?恰恰相反,我们来详细解释一下哎。

这是为什么(max_value - min_value + bucketcount)的原因,如果你会了可跳过。

在桶排序中,perBucket 用来确定每个桶中应该容纳的数据范围。计算 perBucket 的公式 perBucket = (max_value - min_value + bucketcount) // bucketcount 包含了加上 bucketcount 的部分,这是为了确保当数据分布比较均匀时,最后一个桶能够包含 max_value

考虑以下情况:

  • max_value - min_value 是数据范围的总大小。
  • bucketcount 是桶的数量。

如果不加 bucketcount,直接进行除法 (max_value - min_value) // bucketcount,那么计算出的 perBucket 将会是每个桶平均应该包含的数据范围大小。但是,这样可能会导致最后一个桶的数据范围不完整,特别是当 max_value - min_value 不能被 bucketcount 整除时。

加上 bucketcount 是为了确保当 max_value - min_value 不能被 bucketcount 整除时,最后一个桶可以包含到 max_value。这是通过扩大总的范围(max_value - min_value + bucketcount),然后再进行除法来实现的。这样,每个桶都会得到一个至少包含 perBucket 个数的范围,并且最后一个桶能够包含 max_value

举一个简单的例子(如果你已经会了可跳过):

假设 max_value = 10min_value = 1bucketcount = 3

如果不加 bucketcount,则 perBucket = (10 - 1) // 3 = 3。这样,三个桶的范围可能是 [1, 3][4, 6],和 [7, 9]10 就会被遗漏。

加上 bucketcount,则 perBucket = (10 - 1 + 3) // 3 = 4。这样,三个桶的范围可以是 [1, 4][5, 8],和 [9, 10],所有数值都被包含在内。

这就是为什么要加上bucketcount的原因,一句话概括就是:

        为了均匀分布元素,保证最后一个桶接受到最大值(最后一个桶装的元素可能大于前面的桶)。

三:

for num in arr:  
        bucketindex = (num - min_value) // perBucket  
        bucket[bucketindex].append(num)  
  
    for i in range(bucketcount):  
        selection_sort(bucket[i])  
  
    idx = 0  
    for i in range(bucketcount):  
        for v in bucket[i]:  
            arr[idx] = v  
            idx += 1

1-3行:这部分代码遍历原始数组 arr 中的每个元素 num。对于每个元素,它计算一个 bucketindex,该索引决定了 num 应该被放入哪个桶中。bucketindex 是通过 (num - min_value) // perBucket 计算得出的,这里使用了整数除法来确保索引是一个整数。然后,num 被添加到对应的桶 bucket[bucketindex] 中。

5-6行:在将所有元素分配到桶中之后,这部分代码遍历每个桶,并对桶中的元素进行排序。这里使用了选择排序算法(selection_sort 函数)来对每个桶中的元素进行排序。

最后:

        这部分代码负责将排序后的桶元素重新组合回原始数组 `arr`。它初始化一个索引 `idx` 为 0,然后遍历每个桶。

        对于每个桶中的元素 `v`,它将其赋值给 `arr[idx]`,并将 `idx` 增加 1,以便下一个元素可以被放置在正确的位置。

        这样,当所有的桶都被遍历完时,原始数组 `arr` 就会被更新为排序后的数组。

总结:

        整体而言,桶排序是一种分配式排序算法,它通过将数组分配到有限数量的桶中,再对每个桶中的元素进行排序(可能使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后将各个桶中的数据取出放入原始数组得到有序序列。桶排序的性能通常取决于数据的分布和桶的数量。对于均匀分布的数据,桶排序可以是非常高效的。

最后喝一口鸡汤^-^:

        假如生活抛来一颗柠檬,你大可以选择把它榨成鲜美的柠檬汁。

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值