算法导论第三版代码python实现与部分习题答案-第八章:线性时间排序(二)

部署运行你感兴趣的模型镜像

8.4 桶排序

算法实现

def bucket_sort(A, num_buckets=None):
    """
    桶排序算法实现(假设输入元素在[0, 1)区间内均匀分布)
    
    参数:
    A: 输入数组,假设元素在[0, 1)区间内
    num_buckets: 桶的数量,默认为len(A)
    
    返回:
    排序后的数组
    """
    if not A:
        return A
    
    n = len(A)
    if num_buckets is None:
        num_buckets = n
    
    # 步骤1: 创建桶
    buckets = [[] for _ in range(num_buckets)]
    
    # 步骤2: 将元素分配到桶中
    for num in A:
        # 计算元素应该放入哪个桶
        bucket_index = int(num * num_buckets)
        # 处理边界情况:当num = 1.0时
        if bucket_index == num_buckets:
            bucket_index = num_buckets - 1
        buckets[bucket_index].append(num)
    
    # 步骤3: 对每个桶内的元素进行排序
    for bucket in buckets:
        # 可以使用任何排序算法,这里使用插入排序(对小数组效率高)
        insertion_sort(bucket)
        # 也可以使用Python内置排序:
        # bucket.sort()
    
    # 步骤4: 按顺序合并所有桶
    result = []
    for bucket in buckets:
        result.extend(bucket)
    
    return result

def insertion_sort(arr):
    """
    插入排序实现(用于桶内排序)
    """
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key

# 更通用的桶排序实现(适用于任意范围的整数)
def bucket_sort_integers(A, num_buckets=None):
    """
    适用于整数的桶排序
    
    参数:
    A: 输入整数数组
    num_buckets: 桶的数量
    
    返回:
    排序后的数组
    """
    if not A:
        return A
    
    n = len(A)
    if num_buckets is None:
        num_buckets = n
    
    # 找到最大值和最小值
    min_val = min(A)
    max_val = max(A)
    
    # 处理所有元素相等的特殊情况
    if min_val == max_val:
        return A[:]
    
    # 创建桶
    buckets = [[] for _ in range(num_buckets)]
    
    # 将元素分配到桶中
    range_val = max_val - min_val
    for num in A:
        # 计算元素应该放入哪个桶
        bucket_index = int((num - min_val) * (num_buckets - 1) / range_val)
        buckets[bucket_index].append(num)
    
    # 对每个桶内的元素进行排序
    for bucket in buckets:
        insertion_sort(bucket)
    
    # 按顺序合并所有桶
    result = []
    for bucket in buckets:
        result.extend(bucket)
    
    return result

运行时间分析

桶排序的总运行时间由三部分组成:分配元素到桶的时间、对每个桶内元素排序的时间、以及合并结果的时间。设 $ n_i $ 表示第 $ i $ 个桶中的元素个数,$ k $ 表示桶的数量,则总运行时间为:

T(n)=Θ(n)+∑i=0k−1O(ni2)+Θ(k) T(n) = \Theta(n) + \sum_{i=0}^{k-1} O(n_i^2) + \Theta(k) T(n)=Θ(n)+i=0k1O(ni2)+Θ(k)

其中:

  • $ \Theta(n) $:分配 $ n $ 个元素到桶的时间
  • $ \sum O(n_i^2) $:对每个桶使用插入排序的时间(插入排序对 $ m $ 个元素耗时 $ O(m^2) $)
  • $ \Theta(k) $:创建 $ k $ 个桶和合并结果的时间

通常选择 $ k = n $(桶数等于元素数),因此:
T(n)=Θ(n)+∑i=0n−1O(ni2) T(n) = \Theta(n) + \sum_{i=0}^{n-1} O(n_i^2) T(n)=Θ(n)+i=0n1O(ni2)


最坏情况分析

当所有元素都落入同一个桶时(如输入已排序且分布不均),有:

  • $ n_0 = n $,其余 $ n_i = 0 $
  • $ \sum_{i=0}^{n-1} O(n_i^2) = O(n^2) $

因此最坏时间复杂度为:
T(n)=Θ(n)+O(n2)=O(n2) T(n) = \Theta(n) + O(n^2) = O(n^2) T(n)=Θ(n)+O(n2)=O(n2)


平均情况分析(输入在 [0,1)[0,1)[0,1) 均匀分布)

假设每个元素独立且等概率地落入 $ n $ 个桶中的任意一个,求期望运行时间 $ E[T(n)] $:

E[T(n)]=Θ(n)+O(∑i=0n−1E[ni2]) E[T(n)] = \Theta(n) + O\left( \sum_{i=0}^{n-1} E[n_i^2] \right) E[T(n)]=Θ(n)+O(i=0n1E[ni2])

定义指示器随机变量:
Xij={1若 A[j] 落入桶 i0否则 X_{ij} = \begin{cases} 1 & \text{若 } A[j] \text{ 落入桶 } i \\ 0 & \text{否则} \end{cases} Xij={10 A[j] 落入桶 i否则

则:
ni=∑j=1nXij n_i = \sum_{j=1}^n X_{ij} ni=j=1nXij

计算 $ E[n_i^2] $:
E[ni2]=E[(∑j=1nXij)2]=E[∑j=1nXij2+∑1≤j≠k≤nXijXik] E[n_i^2] = E\left[ \left( \sum_{j=1}^n X_{ij} \right)^2 \right] = E\left[ \sum_{j=1}^n X_{ij}^2 + \sum_{1 \leq j \neq k \leq n} X_{ij} X_{ik} \right] E[ni2]=E(j=1nXij)2=Ej=1nXij2+1j=knXijXik

利用期望的线性性:
=∑j=1nE[Xij2]+∑1≤j≠k≤nE[XijXik] = \sum_{j=1}^n E[X_{ij}^2] + \sum_{1 \leq j \neq k \leq n} E[X_{ij} X_{ik}] =j=1nE[Xij2]+1j=knE[XijXik]

由于 $ X_{ij} $ 是指示器变量,$ X_{ij}^2 = X_{ij} $,且 $ E[X_{ij}] = \frac{1}{n} $,所以:
E[Xij2]=1n E[X_{ij}^2] = \frac{1}{n} E[Xij2]=n1

当 $ j \neq k $ 时,$ X_{ij} $ 与 $ X_{ik} $ 独立,因此:
E[XijXik]=E[Xij]⋅E[Xik]=1n⋅1n=1n2 E[X_{ij} X_{ik}] = E[X_{ij}] \cdot E[X_{ik}] = \frac{1}{n} \cdot \frac{1}{n} = \frac{1}{n^2} E[XijXik]=E[Xij]E[Xik]=n1n1=n21

代入得:
E[ni2]=∑j=1n1n+∑1≤j≠k≤n1n2=n⋅1n+n(n−1)⋅1n2=1+n−1n=2−1n E[n_i^2] = \sum_{j=1}^n \frac{1}{n} + \sum_{1 \leq j \neq k \leq n} \frac{1}{n^2} = n \cdot \frac{1}{n} + n(n-1) \cdot \frac{1}{n^2} = 1 + \frac{n-1}{n} = 2 - \frac{1}{n} E[ni2]=j=1nn1+1j=knn21=nn1+n(n1)n21=1+nn1=2n1

对所有 $ i $ 求和:
∑i=0n−1E[ni2]=∑i=0n−1(2−1n)=n(2−1n)=2n−1 \sum_{i=0}^{n-1} E[n_i^2] = \sum_{i=0}^{n-1} \left(2 - \frac{1}{n}\right) = n \left(2 - \frac{1}{n}\right) = 2n - 1 i=0n1E[ni2]=i=0n1(2n1)=n(2n1)=2n1

因此期望运行时间为:
E[T(n)]=Θ(n)+O(2n−1)=Θ(n)+O(n)=Θ(n) E[T(n)] = \Theta(n) + O(2n - 1) = \Theta(n) + O(n) = \Theta(n) E[T(n)]=Θ(n)+O(2n1)=Θ(n)+O(n)=Θ(n)


更一般的线性时间条件

即使输入不服从均匀分布,只要满足:
∑i=0k−1ni2=O(n) \sum_{i=0}^{k-1} n_i^2 = O(n) i=0k1ni2=O(n)
即所有桶的大小平方和与 $ n $ 呈线性关系,则桶排序的期望时间仍为 $ \Theta(n) $。这一条件比均匀分布更宽松,适用于许多实际场景。


结论

  • 最坏情况时间复杂度:$ O(n^2) $
  • 平均情况时间复杂度(均匀分布):$ \Theta(n) $
  • 空间复杂度:$ \Theta(n) $
  • 稳定性:是(若桶内排序算法稳定)

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值