Python中的排列——给小伙伴排座位
中等2排列探秘:用Python给小伙伴们排座位
你有没有遇到过这样的问题:三个小伙伴去电影院,四个座位随便坐,到底有多少种不同的坐法?如果让小明、小红、小刚三个人的顺序调换,每一种新的顺序都是一种全新的坐法。这种把一组元素按不同顺序排成一列的方式,就是排列。在Python里,我们可以很轻松地生成所有可能的排列,让枚举不再头疼。
一、什么是排列?用生活故事讲清楚
想象你、小明、小红、小刚四个人去看电影,买了四个连在一起的座位。你们想试试所有可能的坐法,看看谁坐在最左边、谁坐在最右边会有什么不一样。如果你们挨个换位置,会发现:只要顺序不同,就算一种新坐法。比如:
- 小明、小红、小刚、你(从左到右)
- 小红、小明、小刚、你
- 小刚、小明、你、小红
这三种都是不同的排列。那么,从4个人里选出4个人来坐,总共有几种排列方式呢?答案是 4 × 3 × 2 × 1 = 24 种。这个算式叫做“4的阶乘”,写作 4!。阶乘就是:从1乘到那个数,用于计算全排列的数量。
如果只从4个人里选2个人来坐一排(例如只排前两个座位),那么排列数是 4 × 3 = 12 种。一般地,从n个不同元素中取m个排成一列,排列数记作 P(n,m),公式是:
P(n,m) = n × (n-1) × ... × (n-m+1)
当 m=n 时,就是全排列,即 n!。
生活中的排列到处都是:
- 比赛排名:4个同学参加跑步,前三名有多少种可能?
- 密码锁:密码是4位数字,数字不能重复,有多少种密码?
- 抽奖顺序:抽奖箱里抽出的奖品顺序不同,中奖结果也不同。
二、用Python轻松生成排列:itertools.permutations
Python自带一个强大的工具包——itertools,里面有一个函数叫 permutations,专门用来生成排列。使用时需要先导入 itertools。
基本用法:
itertools.permutations(可迭代对象, 选取个数)
- 第一个参数:要排列的元素,可以是列表、字符串、元组等。
- 第二个参数:选取几个元素来排列。如果不写,默认取全部。
返回的是一个迭代器(可以想象成一个“懒”的生成器,不会一次性全算好),通常我们用 list() 把它转换成列表,就能直接查看每个排列了。每个排列是一个元组,里面元素按顺序排好。
例子1:给三个同学排座位(全排列)
# 导入itertools模块
import itertools
# 定义一个包含三个名字的列表
names = ["小明", "小红", "小刚"]
# 使用permutations生成所有全排列(选3个),并转为列表
all_seats = list(itertools.permutations(names, 3))
# 打印结果
print("三个同学的所有坐法(全排列):")
for seat in all_seats:
print(seat)
print("一共", len(all_seats), "种坐法。")
运行输出:
三个同学的所有坐法(全排列):
('小明', '小红', '小刚')
('小明', '小刚', '小红')
('小红', '小明', '小刚')
('小红', '小刚', '小明')
('小刚', '小明', '小红')
('小刚', '小红', '小明')
一共 6 种坐法。
例子2:从三个同学中选两个排座位(部分排列)
# 只选2个来排
partial_seats = list(itertools.permutations(names, 2))
print("从三个同学中选两个的排列:")
for seat in partial_seats:
print(seat)
print("一共", len(partial_seats), "种。")
输出:
从三个同学中选两个的排列:
('小明', '小红')
('小明', '小刚')
('小红', '小明')
('小红', '小刚')
('小刚', '小明')
('小刚', '小红')
一共 6 种。
注意:('小明', '小红') 和 ('小红', '小明') 是不同的排列,因为顺序不同。
三、新手最容易犯的3个错误
-
忘记导入itertools
直接写permutations(...)会报错NameError。一定要在文件开头写import itertools。 -
把列表/list当第二个参数传错了
permutations的第二个参数是整数,代表选几个元素。如果你不小心传了一个列表,比如itertools.permutations(names, [2]),就会报错TypeError。记住:第二个参数是数字。 -
以为排列结果包含了重复元素
如果原始列表里有重复元素(比如名字有重复),permutations会把它们当成不同的元素,所以输出中会出现看起来相同的排列(因为元素值相同但位置不同)。例如["A", "A", "B"]的排列中会有两个('A', 'A', 'B')吗?实际上不会,因为两个'A'被认为是不同的对象,但值相同,所以会出现重复值——新手可能以为用集合去重就行。其实如果想得到不重复的排列,最好先确保元素唯一,或者使用set再转成列表。
四、完整示例:给四个小伙伴排座位并计数
让我们结合一个完整的场景:你和三个小伙伴(共4人)去看电影,四个座位全坐满。你想知道所有可能的坐法,并且数一数有多少种。下面是一个完整的可运行代码:
# 导入itertools模块
import itertools
# 四个人的名字列表
friends = ["你", "小明", "小红", "小刚"]
# 生成全部4人的全排列(选4个)
all_arrangements = list(itertools.permutations(friends, 4))
# 输出每种坐法
print("=== 四个人的所有坐法(共", len(all_arrangements), "种) ===")
for i, arrangement in enumerate(all_arrangements, 1):
# 从左到右依次是座位1到4
print(f"第{i}种: {arrangement[0]}、{arrangement[1]}、{arrangement[2]}、{arrangement[3]}")
运行结果(部分):
=== 四个人的所有坐法(共 24 种) ===
第1种: 你、小明、小红、小刚
第2种: 你、小明、小刚、小红
...
第24种: 小刚、小红、小明、你
进一步思考: 如果只安排前两个座位(选2个人),那么排列数就是 4 × 3 = 12 种,代码只需将 4 改成 2 即可。
五、更多生活小例子
- 班级值日表:从5个同学中选3个人分别打扫教室、擦黑板、倒垃圾,有多少种分工方案?用
permutations(同学列表, 3)就能列出。 - 抽奖顺序:3个奖品(特等奖、一等奖、二等奖)由5个人抽,每人只抽一次且不重复,中奖顺序有多少种?排列数 = 5×4×3 = 60种。
- 手机手势密码:3×3的点阵,如果规定只能连4个不同点,有多少种手势?其实就是从9个点选4个的排列,数量巨大。
这些场景都能用 permutations 快速枚举出来。
六、相关知识点指引
学会了排列,下一步可以了解一下:
- 组合(combinations):不关心顺序,只关心选哪些元素。比如从3个水果中选2个,不考虑先后,那么(苹果、香蕉)和(香蕉、苹果)是同一种组合。Python中有
itertools.combinations。 - 笛卡尔积(product):把多个集合的元素两两组合,比如掷两个骰子的所有点数对。用
itertools.product。 - 迭代器原理:
permutations返回的是一个迭代器,可以用next()逐个取出元素,节省内存。在元素很多(比如10个元素的全排列有3628800种)时,用迭代器比一次性生成列表要高效得多。
排列是组合数学的基础,掌握了它,你就能更自信地处理各种排序问题。快去试试给身边的小伙伴们排个座吧!
例题精讲
有5个小伙伴(小明、小红、小刚、小丽、小华)排成一排看电影,问有多少种不同的排列方式?
使用 itertools.permutations 可以生成排列,该函数的第一个参数是可迭代对象,第二个参数是排列的长度(若不指定则默认可迭代对象的长度)。
从4个小伙伴(A、B、C、D)中选出3个排座位,要求顺序不同算不同排列,有多少种方式?
排列与顺序有关,组合与顺序无关。
以下代码用于打印出三个小伙伴['Alice','Bob','Charlie']的所有排列,请补全代码:
import itertools
lst = ['Alice','Bob','Charlie']
for p in ___: # 使用itertools的排列函数
print(p)