递归算法——(C++)求n个元素的全排列问题的分析与实现

1.问题

求n个元素的全排列

2.分析

n=1时:

a1

n=2时:

a1 a2
a2 a1

n=3时:

a1 a2 a3
a1 a3 a2
a2 a1 a3
a2 a3 a1
a3 a2 a1
a3 a1 a2

在n=3时,得到6种全排列,从上到下两两分组可以得到3组,可以发现下面的规律:

  • 第一组以a1开始,之后连接a2和a3的全排列,以此类推。

  • 将第一组的a1与a2交换位置可以得到第二组,将第一组的a1与a3交换位置可以得到第三组。

那么可以找到递归调用:在n个有序元素中,第一个元素连接后n-1个元素的全排列;将第1个元素与第2个元素互换,继续连接后n-1个元素的全排列;以此类推… …;最终将第n-1个元素与第n个元素互换。当后n-1个元素只剩一个时,就打印整个有序元素序列。

3.实现(C++)

/**< 递归求解全排列问题 */

#include <iostream>
#include <stdio.h>
#include<string>
using namespace std;

#define ARRAY_LEN 3 //定义数组长度

//用于打印字符数组a
void print_array(char a[])
{
    for(int i=0; i<ARRAY_LEN; i++)   printf("%c",a[i]);
    printf("\n");
}

//用于打印缩进
void print_tab(int n){
    string str="";
    for(int i=0;i<n;i++) str+="\t";
    cout<<str;
}

// 求字符数组a[0:n-1]中所有字符从下标k到n-1的全排列
void range(char a[],int k,int n)
{

    print_tab(k);
    printf("当前调用的是range(a,%d,%d):\n",k,n);
    if(k==n)
    {
        print_tab(k);
        printf("目标输出-----------------");
        print_array(a);
    }
    else
    {
        for (int i=k; i<n; i++)
        {
            //打印信息
            print_tab(k);
            printf("a[%d]与a[%d]交换,交换前数组a为:",k,i);
            print_array(a);
            
            //交换
            char temp=a[i];
            a[i]=a[k];
            a[k]=temp;
			
			//打印信息
            print_tab(k);
            printf("交换后数组a为:");
            print_array(a);
			
			//递归调用
            range(a,k+1,n);
            
            //复原
            temp=a[i];
            a[i]=a[k];
            a[k]=temp;
			
			//打印信息
            print_tab(k);
            printf("复原后数组a为:");
            print_array(a);
        }
    }
    //打印信息
    print_tab(k);
    printf("range(a,%d,%d):调用结束\n",k,n);
}

int main()
{
    char a[ARRAY_LEN]= {""};
    //初始化字符数组a[n]为字母表顺序的大写字母
    for(int i=0; i<ARRAY_LEN; i++) a[i]= 65+i;

    //主函数调用
    range(a,0,ARRAY_LEN);

    return 0;
}

4.结果

当n=2时,可以清晰看到整个调用过程:
在这里插入图片描述
n>2时就可以删去打印信息的部分(眼花缭乱)…

/**< 递归求解全排列问题 */

#include <iostream>
#include <stdio.h>
#include<string>
using namespace std;

#define ARRAY_LEN 3 //定义数组长度

//用于打印字符数组a
void print_array(char a[])
{
    for(int i=0; i<ARRAY_LEN; i++)   printf("%c",a[i]);
    printf("\n");
}

// 求字符数组a[0:n-1]中所有字符从下标k到n-1的全排列
void range(char a[],int k,int n)
{
    if(k==n)
    {
        printf("目标输出-----------------");
        print_array(a);
    }
    else
    {
        for (int i=k; i<n; i++)
        {
            //交换
            char temp=a[i];
            a[i]=a[k];
            a[k]=temp;
			
			//递归调用
            range(a,k+1,n);
            
            //复原
            temp=a[i];
            a[i]=a[k];
            a[k]=temp;

        }
    }
}

int main()
{
    char a[ARRAY_LEN]= {""};
    //初始化字符数组a[n]为字母表顺序的大写字母
    for(int i=0; i<ARRAY_LEN; i++) a[i]= 65+i;

    //主函数调用
    range(a,0,ARRAY_LEN);

    return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值