递归-输出整数的全排列

递归

题目

1、本实验要求用递归方法而不是循环方法实现,更不可以直接用语言内置的函数。
2、输入1-20个大于0的正整数(1、2、3或者100、200、300),输入0作为结束,0不参与排列。
3、输出这几个整数的全排列,每个数之间用英文半角","隔开,中间不要有空格,
每个排列单独一行。

分析

每一层递归决定“第 k 位放哪个还没用过的数”,然后递归到第 k+1 位;选完并回溯时,把该数标记为未使用,供其他分支再选。

通俗:要实现利用递归输出整数的所有全排列,可以将每一次递归都是做一个小整数串的递归,上一层需要决定的是起始元素是什么,下一层重复操作;喂给下一层递归的元素有几个、内容是什么由num和ans共享

代码分析

#include <iostream>
using namespace std;

int num[25] ;
bool used[25] ;
int ans[25] ;
int n = 0 ;
void perm ( int k ){
if ( k == n ){
for ( int i = 0 ; i < n ; i++ ){
if ( i > 0 ) cout << ',' ;
cout << ans[i] ;
}
cout << endl ;
return ;
}
for ( int i = 0 ; i < n ; i++ ){
if ( !used[i] ) {
used[i] = true ;
ans[k] = num[i] ;
perm( k+1 ) ;
used[i] = false ;
}
}
}

int main(){
cout << "input" << endl << "output" << endl ;
int x ;
while( n<=20 ){
cin >> x ;
if ( x == 0 ) break;
num[ n ] = x ;
n++;
}
perm( 0 ) ;
cout << "end";
return 0 ;
}

思路探讨

  1. 我想不到怎么去设一个used【i】这个数组用于回溯?

    • 过程思考:

      • 假设你是人,给你三个数 1、2、3,让你写出所有排列。你会怎么做?

        你大概率会这样:

      1. 第一位放 1。
      2. 第二位……1 已经用过了,不能再用,所以只能放 2 或 3。
      3. 第二位放 2,第三位……1、2 都用过了,只能放 3。
      4. 得到一个排列 1,2,3。
      5. 退回去,第二位改放 3,第三位只能放 2,得到 1,3,2。
      6. 再退回去,第一位改放 2……

      你在做这件事的时候,脑子里一直在判断一件事:

      “这个数,我前面是不是已经用过了?”

      对,就是这个判断。used[] 数组,就是把这个“脑子里记着哪些数用过了”变成代码。

      需要将人类思考"我这个用过了,还能不能再用"的思考结果转换成机器标记

    • 没有used标记:

      for (int i = 0; i < n; i++) {
      ans[k] = num[i];
      perm(k + 1);
      }

      输出结果

      没有标注的情况会重复利用数据

      • 修改成这样,为什么输出结果是一样的?

        for (int i = 0; i < n; i++) {
        if ( !used[i] ){
        used[i] == true ;
        ans[k] = num[i];
        perm(k + 1);
        used[i] == false ;
        }
        }

        因为你把赋值写成比较了!!!!!

posted @ 2026-10-16 17:54  CapyAlice  阅读(7)  评论(0)    收藏  举报