CC++ & Algorithm

Python中的排列——给小伙伴排座位

中等2
语言版本:C++Python
概述:通过排座位的例子,讲解排列的概念以及如何使用Python的permutations函数生成所有可能的排列。

排列探秘:用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个错误

  1. 忘记导入itertools
    直接写 permutations(...) 会报错 NameError。一定要在文件开头写 import itertools

  2. 把列表/list当第二个参数传错了
    permutations 的第二个参数是整数,代表选几个元素。如果你不小心传了一个列表,比如 itertools.permutations(names, [2]),就会报错 TypeError。记住:第二个参数是数字。

  3. 以为排列结果包含了重复元素
    如果原始列表里有重复元素(比如名字有重复),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种)时,用迭代器比一次性生成列表要高效得多。

排列是组合数学的基础,掌握了它,你就能更自信地处理各种排序问题。快去试试给身边的小伙伴们排个座吧!

例题精讲

1单选题

有5个小伙伴(小明、小红、小刚、小丽、小华)排成一排看电影,问有多少种不同的排列方式?

A120
B25
C5
D20
2判断题

使用 itertools.permutations 可以生成排列,该函数的第一个参数是可迭代对象,第二个参数是排列的长度(若不指定则默认可迭代对象的长度)。

3单选题

从4个小伙伴(A、B、C、D)中选出3个排座位,要求顺序不同算不同排列,有多少种方式?

A24
B12
C4
D6
4判断题

排列与顺序有关,组合与顺序无关。

5填空题
以下代码用于打印出三个小伙伴['Alice','Bob','Charlie']的所有排列,请补全代码:
import itertools
lst = ['Alice','Bob','Charlie']
for p in ___:  # 使用itertools的排列函数
    print(p)