排列的算法(一)——字典序算法

本文详细解释了如何使用字典序法生成全排列,并提供了算法的实现代码,帮助理解全排列生成的过程。

从n个不同元素中取出n个元素的排列,称为n个不同元素的全排列。

可以证明,n个元素的全排列的总数是n!。

全排列的生成算法就是对于给定的元素集合,用有效的方法将所有可能的全排列无重复无遗漏地列举出来。

n个不同元素的排列都可以与n个自然数12、……,n的排列一一对应,所以,这里就以n个数字的排列为例说明排列的生成算法。全排列的生成算法就是讨论怎样从一个排列生成它一个新的排列的方法。

1.字典序算法

不同的排列,可以从左到右逐个比较对应的元素的顺序来决定他们的先后顺序。设有集合{12、……n-1n}的两个排列 a0a1 ……aj……an-1和 b1b2……bj……bn-1bn,从左端开始,逐个比较它们的对应元素的大小,如果出现对应数字不相同的第一个位置为 j,并且aj<bj,则a0a1 ……aj……an-1就排在b0b1……bj……bn-1的前面。例如对于5个数字的排列1235412345,两个排列的前三个数字相同,出现不同数字的位置是 j=3,而排列12354的第四个数字5在排列12345的第四个数字4之后,所以排列12345在前,排列12354在后。根据这样的规定,5个数字的所有的排列中,第一个排列是12345,最后一个是54321。这种判断排列顺序的方法称为字典序法。

根据字典序法生成所有全排列的算法如下:

设P是集合{12、……n-1n}的一个全排列:P=p1p2……pj-1pjpj+1……pn(1p1、 p2、……、pn≤n-1

第一步:从排列的右端开始,找出第一个比右边数字小的数字的序号j,即j=max{i|pi<pi+1 ,i>j}

第二步:在pj 的右边的数字中,找出所有比pj 大的数字中最小的数字pk,即k=min{i|pi>pj ,i>j}

第三步:交换pi,p

第四步:再将排列右端的递减部分pj+1pj+2……pn倒转,就得到了一个新的排列P'=p1p2……pj-1pjpn……kpj+2pj+1。

例如839647521是数字19的一个排列。从它生成下一个排列的步骤如下: 

自右至左找出排列中第一个比右边数字小的数字4     839647521

在该数字后的数字中找出比4大的数中最小的一个5   839647521

54交换                                    839657421

7421倒转                                     839651247

所以839647521的下一个排列是                    839651247

为了得到集合{12、……n-1n}的全体全全排列,可以从原始排列12……n开始,按照字典序法逐个生成它们的后继排列。当得到的后继排列是最后一个n……21时就结束。

字典序算法的程序代码:

//字典序算法

//输入:排列元素个数n

//输出:n个元素的排列

#include <iostream>

#include <iomanip>

using namespace std;

 

void dict(int *p,int n);

void output(int *p,int n);

int t;

 

int main(void)

{

freopen("in.dat","r",stdin);

int n,*p;

    while(cin>>n)

{

p=new int[n];

for(int i=0;i<n;i++)

p[i]=i+1;

t=0;

             dict(p,n);

}

return 0;  

}

 

void dict(int *p,int n)

{

int i,j;

while(1)

{

output(p,n);                     

for(i=n-2;i>=0;i--)               

   if(p[i]<p[i+1])

break;

if(i<0)                           

break;                  

for(j=n-1;j>=0;j--)               

if(p[j]>p[i])

break;

swap(p[i],p[j]);

j=n-1;

while(i<j)

swap(p[++i],p[j--]);

}

}

 

void output(int *p,int n)

{

     Cout<<setw(5)<<++t<<”:”;

for(int i=0;i<n;i++)

cout<<setw(3)<<p[i];

cout<<endl;

}

### Python 中基于字典序排列组合算法实现 #### 字典序排列的概念 字典序种常见的排序方式,在字符串处理以及排列组合生成中有广泛应用。对于给定的组字符,可以依据这些字符组成的字符串之间的自然顺序来定义它们之间的小于关系[^1]。 #### 使用标准库函数 `itertools.permutations` 和自定义逻辑相结合的方式 虽然Python内置模块`itertools`提供了方便快捷的方法用于生成全排列,但是为了遵循特定需求——即按照字典序输出结果,则需要额外编写代码确保每次迭代都能得到下个更大的排列直到遍历所有可能性为止[^2]。 ```python from itertools import permutations def next_permutation(nums): n = len(nums) # Find the largest index k such that nums[k] < nums[k + 1]. If no such index exists, just reverse nums and done. for k in range(n-2, -1, -1): if nums[k] < nums[k + 1]: break else: nums.reverse() return False # Find the largest index l greater than k such that nums[k] < nums[l]. for l in range(n-1, k, -1): if nums[k] < nums[l]: break # Swap nums[k] and nums[l] nums[k], nums[l] = nums[l], nums[k] # Reverse the sequence from nums[k + 1] up to and including the final element nums[n-1] nums[k+1:] = reversed(nums[k+1:]) return True # Example usage with a list of characters ['a', 'b', 'c'] characters = ['a', 'b', 'c'] perm_set = set(permutations(characters)) sorted_perms = sorted([''.join(p) for p in perm_set]) for item in sorted_perms: print(item) current_list = list('abc') while True: print(''.join(current_list)) has_next = next_permutation(current_list) if not has_next: break ``` 上述代码片段展示了如何利用Python自带的数据结构特性配合简单的循环控制语句完成对输入序列按字典序逐个打印其后续排列的任务。通过这种方式不仅可以获得全部不同的排列形式而且保证了每步操作后的状态总是当前未访问过的最小者之[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值