算法设计与分析:基于C++编程语言的描述
上QQ阅读APP看书,第一时间看更新

1.4.3 排列问题

1.问题描述

n个元素,它们的编号为1,2,…,n,排列问题的目的是生成这n个元素的全排列。采用一个具有n个存储单元的数组A来存放所生成的排列,假定初始时n个元素已按编号次序由小到大存放在数组A中,即数组中存放的是元素的编号。

2.算法设计思路

为解决该问题,首先要进行认真思考,以便找出生成元素全排列算法的内在规律性,也即分析出递归关系,还需找到算法的停止条件,进而推导出递归关系式,最终设计出递归函数,即构建递归体。

具体设计过程如下:

(1)将规模为n的排列问题转化为规模为n-1的排列问题。

步骤1:数组的首元素定为1,即排列的第一个元素为1,还需要生成后面n-1个元素的全排列。

步骤2:将数组的第一个元素和第二个元素互换,使得数组的首元素为2,即排列的第一个元素为2,还需要生成后面n-1个元素的全排列。

……

步骤n:将数组的第一个元素和第n个元素互换,使得数组的首元素为n,即排列的第一个元素为n,还需要生成后面n-1个元素的全排列。

(2)将规模为n-1的排列问题转化为规模为n-2的排列问题。

对于上述n个步骤,每一步均要按以下步骤进行操作,以步骤1为例进行讲述。

步骤1-1:数组的第二个元素为2,即排列的第二个元素为2,还需要生成后面n-2个元素的全排列。

步骤1-2:数组的第二个元素和第三个元素互换,使得数组的第二个元素为3,即排列的第二个元素为3,还需要生成后面n-2个元素的全排列。

……

步骤1-(n-1):数组的第二个元素和第n个元素互换,使得数组的第二个元素为n,即排列的第二个元素为n,还需要生成后面n-2个元素的全排列。

同理,将问题的规模一级一级降至1,1个元素的排列是它本身,此时到达递推的停止条件。数组中的元素即为1个排列,然后进行回归依次得到其他的排列。

3.算法描述

从上述算法的设计过程可以看出,使用递归技术来解决全排列问题是很容易的。

假定排列算法perm(Akn)的功能是:生成数组A后面k个元素的排列。当k=1时,只有一个元素,已构成一个排列。当1<kn,可由算法perm(Ak-1,n)生成数组A后面k-1个元素的排列,为完成数组A后面k个元素的排列,需要逐一将数组第n-k个元素与数组中第n-kn-1个元素互换,每互换一次,就执行一次perm(Ak-1,n)。该问题的算法描述如下:

     void perm(int A[],int k,int n )         //参数k是当前递归层需完成排列的元素个数
        {
           int i;
           if(k==1)                          //已构成一个排列,将其输出
                for(i=0;i<n;i++){
                     cout<<A[i]<<;
                cout<<endl;}
            else
                for(i=n-k;i<n;i++)
                  {
                     swap(A[i],A[n-k]);      //swap为完成元素互换的函数
                     perm(A,k-1,n);
                     swap(A[i],A[n-k]);
                  }
        }