全排列算法的正确性证明

算法老师给了个苦逼的全排列的证明问题,霎时费心。现整理如下:

分析以下生成排列算法的正确性和时间效率:(为方便测试,源代码附在最后)

              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);
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值