function ps=permutations(n)
%PERMUTATIONS 产生[n]所有置换
% ps = permutations( n ) 输入正整数n,用换位法产生[n]的所有置换,并按行存入ps返回。
%$Author: WBC$ $Date: 2005/9/30$ $ref: 卢开澄 卢华明 组合数学(第3版) p28-30$
%初始化
ps=zeros(prod(1:n),n);
A=1:n; %用于存储排列的行向量
D=1:n; % D(k)表示k在{1,2,..,k}这k个数中的位置,即在保持顺序不变的前提下去掉比k大的数后k所在的位置.
% 为了程序上的统一, 在向左走时, 位置是从1计数, 在向右走时, 位置是从0计数. 这样, 假如当前
% 置换中某处于活动的最大数将要走的下一个位置是p, 那么在向左走时, 该最大数的位置是p+1, 因为
% 从1开始计数, 所以p和p+1就是数组A中的实际位置, 从而交换A(p)和A(p+1)就得到了下一个置换,
% 在向右走时, 该最大数的位置是p-1, 因为从0开始计数, 所以p-1和p在数组A中的实际位置都要加1,
% 变为p和p+1, 从而也是交换A(p)和A(p+1)就得到了下一个置换. 显然, 无论是向左还是向右, 我们在
% 交换时的公式是相同的. 当然, 如果不这样做, 可以通过判断实现交换, 效率就低一些.
E=-ones(1,n);%当E(k)=-1时表示数k的箭头方向指向左方, 当E(k)=1时表示数k的箭头方向指向右方
%主循环
ok=1; %一个用来判断循环是否结束的变量
loop=0; %用于标记当前产生的置换要存入ps的行
while ok
ok=0; %如果下面的程序不能使ok变为1,就结束整个循环,表明已经产生了所有的置换
loop=loop+1;
ps(loop,:)=A;
q=0; %可以看作数k在A中位置相对于在{1,2,..,k}中位置的偏移量
for k=n:-1:2
D(k)=D(k)+E(k); %试探下一个位置
p=D(k); %数k在下一个置换的{1,2,...,k}中的位置
if p>0 && p<k % 试探下一个位置成功, 表示数k走到{1,2,...,k}的中间位置
p=p+q;
r=A(p); A(p)=A(p+1); A(p+1)=r; %交换两个位置p和p+1上的元素
ok=1;
break;
elseif p==k %表示数k走到{1,2,...,k}的最右端
E(k)=-1; %数k改变方向
else %此时p==0, 表示数k走到{1,2,...,k}的最左端
E(k)=1; %数k改变方向
q=q+1; %当数k走到左端时才会使其右边的数的下标有1个偏移
end
end
end