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)})")
核心逻辑说明:
- 索引追踪法:维护一个索引列表
indices,表示当前组合在原列表中的位置索引 - 字典序生成:通过递增索引的方式按字典序生成所有组合
- 关键步骤:
- 从右向左找到第一个可以递增的索引(该索引未达到最大值)
- 递增该索引,并将其右侧的所有索引重置为连续递增的值
- 根据索引从原列表取出对应元素生成组合
算法特点:
- 时间复杂度:O(C(n, r)),每个组合生成时间恒定
- 空间复杂度:O®,只需存储当前索引
- 使用生成器,内存友好
一句话总结:用索引递增模拟组合的字典序生成。
什么叫不放回组合的函数?

