Python 中的桶排序算法_排序算法

桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。

桶排序如何工作?

在进入其确切实现之前,让我们先了解一下算法的步骤:

  1. 设置空桶列表。为数组中的每个元素初始化一个桶。
  2. 遍历桶列表并插入数组中的元素。每个元素的插入位置取决于输入列表及其最大元素。我们最终可以在每个桶中获取元素。这将在算法的可视化呈现中详细说明。0..n
  3. 对每个非空桶进行排序。您可以使用任何排序算法来执行此操作。由于我们使用的是一个小型数据集,因此每个桶不会有很多元素,因此插入排序在这里为我们创造了奇迹。
  4. 按顺序访问桶。对每个桶的内容进行排序后,当它们串联起来时,它们将生成一个列表,其中的元素根据您的条件进行排列。

让我们看一下算法如何工作的可视化呈现。例如,假设这是输入列表:

Python 中的桶排序算法_插入排序_02

最大的元素是1.2 ,列表的长度是6 。使用这两个size,我们将计算出每个桶的最佳值。我们将通过将最大的元素除以列表的长度来获得这个数字1.2/6。在我们的例子中,它是0.2

通过将元素的值除以 this,我们将得到每个元素各自桶的索引。

现在,我们将创建空桶。我们将拥有与列表中的元素相同数量的桶:

Python 中的桶排序算法_插入排序_03

我们将此元素放在索引为 :5

Python 中的桶排序算法_桶排序_04

同样,下一个元素将索引到 0.22/0.2 = 1.1。由于这是一个十进制数,我们将对其进行下限。这四舍五入为 1,我们的元素被放置在第二个桶中:

Python 中的桶排序算法_桶排序_05

重复此过程,直到我们将最后一个元素放入其各自的桶中。我们的桶现在看起来大致如下:

Python 中的桶排序算法_桶排序_06

现在,我们将对每个非空桶的内容进行排序。我们将使用插入排序,因为它在这样的小列表中是不败的。插入排序后,桶如下所示:

Python 中的桶排序算法_排序算法_07

现在,只需遍历非空桶并将列表中的元素连接起来即可。它们已分类并准备就绪:

Python 中的桶排序算法_插入排序_08

Python 中的桶排序实现

Python 中实现该算法。让我们从函数bucket_sort()本身开始:

def bucket_sort(input_list):
    # Find maximum value in the list and use length of the list to determine which value in the list goes into which bucket 
    max_value = max(input_list)
    size = max_value/len(input_list)

    # Create n empty buckets where n is equal to the length of the input list
    buckets_list= []
    for x in range(len(input_list)):
        buckets_list.append([]) 

    # Put list elements into different buckets based on the size
    for i in range(len(input_list)):
        j = int (input_list[i] / size)
        if j != len (input_list):
            buckets_list[j].append(input_list[i])
        else:
            buckets_list[len(input_list) - 1].append(input_list[i])

    # Sort elements within the buckets using Insertion Sort
    for z in range(len(input_list)):
        insertion_sort(buckets_list[z])
            
    # Concatenate buckets with sorted elements into a single list
    final_output = []
    for x in range(len (input_list)):
        final_output = final_output + buckets_list[x]
    return final_output

我们已经计算了参数。然后,我们实例化了空桶的列表,并根据它们的值和每个桶的元素插入了元素。

插入后,我们调用每个桶:insertion_sort()

def insertion_sort(bucket):
    for i in range (1, len (bucket)):
        var = bucket[i]
        j = i - 1
        while (j >= 0 and var < bucket[j]):
            bucket[j + 1] = bucket[j]
            j = j - 1
        bucket[j + 1] = var

有了这些,让我们填充一个列表并对其执行 Bucket 排序:

def main():
    input_list = [1.20, 0.22, 0.43, 0.36,0.39,0.27]
    print('ORIGINAL LIST:')
    print(input_list)
    sorted_list = bucket_sort(input_list)
    print('SORTED LIST:')
    print(sorted_list)

运行此代码将返回:

Original list: [1.2, 0.22, 0.43, 0.36, 0.39, 0.27]
Sorted list: [0.22, 0.27, 0.36, 0.39, 0.43, 1.2]

桶排序时间复杂度

最坏情况

如果我们使用的集合范围很短(就像我们在示例中一样),单个桶中包含许多元素是很常见的,其中很多桶都是空的。

如果所有元素都属于同一个桶,则复杂性完全取决于我们用于对桶本身的内容进行排序的算法。

由于我们使用的是插入排序 - 当列表以相反的顺序排列时,其最坏情况的复杂性会大放异彩。因此,桶排序 的最坏情况复杂度也是O(n2).

最佳情况

最好的情况是已经对所有元素进行排序。此外,元素是均匀分布的。这意味着每个桶将具有相同数量的元素。

话虽如此,创建桶需要 O(n),插入排序需要 O(k),从而为我们提供了 O(n+k) 的复杂度。

一般情况

一般情况发生在绝大多数现实生活中。我们要排序的集合是随机的,在这种情况下,桶排序 需要 O(n) 来完成,因此还是非常高效的