算法老师给了个苦逼的全排列的证明问题,霎时费心。现整理如下:
分析以下生成排列算法的正确性和时间效率:(为方便测试,源代码附在最后)
HeapPermute(n)
//实现生成排列的Heap算法
//输入:一个正正整数n和一个全局数组A[1..n]
//输出:A中元素的全排列
if n= 1
writeA
else
fori ←1 to n do
HeapPermute(n-1)
if nis odd
swapA[1]andA[n]
else swap A[i]and A[n]
下面是我的证明:
当n=1时,输出序列是1,成立。
当n=2时,输出序列是1 2;2 1,成立。
假设当n=2k时,输出的是全排列序列,并且满足经过HeapPermute(n)后,数组中的值循环右移一位;当n=2k+1时,输出的是全排列序列,并且满足经过HeapPermute(n)后,数组中的值不变。
所以当n=2k+2时:
由于n=2k+2是偶数,所以当n进入HeapPermute方法以后,会首先执行HeapPermute(2k+1),由假设可知,对于奇数2k+1,HeapPermute(2k+1)出来后,数组中的值得位置并不会发生变化,且是前2k+1个值得全排列。因此可以保证在fori<-1 to n的整个过程中,swap(A[i],A[n])语句使得原数组中的每一个值都会到第2n+2的位置,而对HeapPermute(2k+1),每个过程都是对这2k+1个数的全排列,所以可得HeapPermute(2k+2)会得到2k+2个数的全排列。
n次循环下来可见原来的1,2,….2k+1顺次朝后挪了一个位置,第一个位置被2k+2占据,因此满足当n=2k+2是偶数时,数组中的元素循环右移一位。
当n=2k+3时:
由于n=2k+3是奇数,所以当n进入HeapPermute方法以后,会首先执行HeapPermute(2k+2),由假设可知,对于偶数2k+2,HeapPermute(2k+2)出来后,数组中的值得位置会循环右移一位,并且输出前2k+2个元素的全排列。因此可以保证在for i<-1 to n的整个过程中,swap(A[1],A[n]),依次把A[1..n]的数据放到最后一个位置A[n],然后对前2k+2个元素进行全排列,HeapPermute(2k+2)。所以HeapPermute(2k+3)后,输出的是2k+3个元素的全排列,并且满足出了过程后,数组中元素的顺序不变。
这种方法的内在机制是什么?
首先我们可以看到
源代码-------------------
#define N 4
#include <stdio.h>
#include <stdlib.h>
int A[9]={1,2,3,4,5,6,7,8,9};
FILE * out;
inline swap(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void print()
{
int j=0;
for(j=0;j<N;j++)
fprintf(out,"%d ",A[j]);
fprintf(out,"\n");
}
void HeapPermute(int n)
{
int i=0;
if(n==1)
print();
else
{
for(i=0;i<n;i++)//奇数项使得不改变顺序,偶数项使得循环左移
{
HeapPermute(n-1);
if(n%2)
swap(A[0],A[n-1]);
else
swap(A[i],A[n-1]);
}
}
}
void main()
{
out=fopen("jieguo.txt","w");
HeapPermute(N);
fprintf(out,"--------------------------------");
print();
exit(1);
}