演算法老師給了個苦逼的全排列的證明問題,霎時費心。現整理如下:
分析以下產生排列演算法的正確性和時間效率:(為方便測試,原始碼附在最後)
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);
}