Python中不使用itertools库,只使用循环如何实现排列组合里的不放回组合函数?

null
Python中不使用itertools库,只使用循环如何实现排列组合里的不放回组合函数?

5 回复

可以,不过我许久之前的实现比较丑


def combinations_no_itertools(iterable, r):
    """
    实现不放回组合(组合数C(n, r))
    参数:
        iterable: 可迭代对象
        r: 组合长度
    返回:
        所有组合的列表
    """
    pool = list(iterable)
    n = len(pool)
    
    if r > n:
        return []
    
    # 初始化索引列表
    indices = list(range(r))
    
    # 第一个组合直接生成
    yield tuple(pool[i] for i in indices)
    
    while True:
        # 从右向左找到第一个可以递增的索引
        for i in reversed(range(r)):
            if indices[i] != i + n - r:
                break
        else:
            # 所有索引都已达到最大值,结束
            return
        
        # 递增找到的索引
        indices[i] += 1
        
        # 重置该索引右侧的所有索引
        for j in range(i + 1, r):
            indices[j] = indices[j - 1] + 1
        
        # 生成当前组合
        yield tuple(pool[i] for i in indices)

# 使用示例
if __name__ == "__main__":
    # 测试数据
    data = ['A', 'B', 'C', 'D']
    r = 3
    
    print(f"从{data}中取{r}个元素的所有组合:")
    for combo in combinations_no_itertools(data, r):
        print(combo)
    
    # 验证数量
    result = list(combinations_no_itertools(data, r))
    print(f"\n总组合数:{len(result)} (C({len(data)}, {r}) = {len(result)})")

核心逻辑说明:

  1. 索引追踪法:维护一个索引列表indices,表示当前组合在原列表中的位置索引
  2. 字典序生成:通过递增索引的方式按字典序生成所有组合
  3. 关键步骤
    • 从右向左找到第一个可以递增的索引(该索引未达到最大值)
    • 递增该索引,并将其右侧的所有索引重置为连续递增的值
    • 根据索引从原列表取出对应元素生成组合

算法特点:

  • 时间复杂度:O(C(n, r)),每个组合生成时间恒定
  • 空间复杂度:O®,只需存储当前索引
  • 使用生成器,内存友好

一句话总结:用索引递增模拟组合的字典序生成。

什么叫不放回组合的函数?

回到顶部