全排列问题详解【递归实现】

描述

给定一个正整数n,输出1~n的全排列

分析1

首先,根据递归的思想,我们可以把求1~n的全排列这个大问题分解为先固定1,求剩下的n-1个数的全排列,在固定2,固定3……依次类推。而对于剩下的这n-1个数,同样采用这种方法,取里面的第一个数,放到当前排列的第一个位置,再取第二个数放到第一个位置……
即:对于1,2,3,4……n,这n个数,分别求
1,2,3,……,n
      2,3,……,n
      3,……,n
       ……
            n
      4,……,n
       ……
            n
      ……
      n,……,n-1
      3,2,……,n
      ……
    ……
      n,1,……,n-1
2,1,3,……,n
3,1,2,……,n
……
n,1,2,……,n-1
对于分别以1到n开头,可以通过交换的思想来实现,在递归前先将待排元素与当前排列的第一个元素进行交换,在递归结束时,还应交换回来,如1,2,3,在处理2开头的排列时,先将2和1交换,将2固定到排列的第一个位置。得到2,1,3,然后处理1和3。待处理完毕输出以2开头的全部排列后,递归返回到2,1,3这个状态,在进行一次交换,将2和1交换回来,得到1,2,3这个原始状态,在进入下一轮,继续将3和1交换,得到3,1,2,然后进行同样的处理。

代码实现:
#include <iostream>

using namespace std;

void swap(int &a, int &b) {//交换
    int t = a;
    a = b;
    b = t;
}

void perm(int num, int n, int a[]) {
    if (num == n) {//已处理完n个元素,可输出一组排列
        for (int i = 1; i <= n; ++i) {
            cout << a[i] << " ";
        }
        cout << endl;
        return;
    }

    for (int j = num; j <= n; ++j) {
        swap(a[j], a[num]);
        perm(num + 1, n, a);
        swap(a[j], a[num]);
    }
}

int main() {
    int n;
    int a[11];
    cin >> n;
    for (int i = 1; i <= n; i++) {
        a[i] = i;
    }
    perm(1, n, a);
    return 0;
}
输出如下:

在这里插入图片描述

时间复杂度分析

其递归方程为:T(n)=nT(n-1)+n,因而其时间复杂度要略高于n!,可近似为n!。

分析2

从上面的输出可以看到,其并未遵从字典序。故可以采用回溯的策略,构建一棵解空间树 ,进行深度优先搜索,到达叶子结点时即可构成一组排列(从根到叶子的一组完整路径)。每向下扩展一层,试图填入一个数,如果该数已经被其祖先使用过,则不可再使用,应判断下一个数,这样到第n+1层时,表明1到n个数已经全部填入,便可结束本次递归过程,并输出当前排列。并且每当返回上一层后,应将该层所填入的数重新标记为未被使用过。
如图:

在这里插入图片描述

代码实现
#include <iostream>

using namespace std;
bool flag[10] = {false};//标记数组
int permutation[10];//保存当前排列
void dfs(int level, int n) {
    if (level == n + 1) {//如果到达了第n+1层,则输出
        for (int j = 1; j <= n; ++j) {
            cout << permutation[j];
        }
        cout << endl;
        return;
    }
    for (int j = 1; j <= n; ++j) {//依次将1到n这几个数填入
        if (flag[j] == false) {//判断当前j是否被用过
            permutation[level] = j;
            flag[j] = true;
            dfs(level + 1, n);//扩展下一层
            flag[j] = false;//递归返回上一层,将j重新标记未被使用
        }
    }
}

int main() {
    int n;
    cin >> n;
    dfs(1, n);
    return 0;
}
时间复杂度分析

第一层有n种选择,第二层有n-1种,第三层有n-2种……故时间复杂度为n!。

输出如下:

在这里插入图片描述

  • 16
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Missヾaurora

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值