字母全排列——递归方法

本文围绕字母全排列算法展开,以含a、b、c、d四个元素的数组为例,分析得出可将问题分解为不同规模子问题。核心代码含两个SWAP函数,分别用于置换首字母和还原字母顺序,最后给出了C++代码实现。
算法分析

 设有一字母数组为:

word = {‘a’,‘b’,‘c’,‘d’…}
假设word当前只有四个与元素,分别为a、b、c、d;

 如果需要将word数组按照全排列打印的话,则所有的结果有4 * 3 * 2 *1 = 24种排列顺序,分别为:

abcd、abdc、acbd、acdb、adcb、adbc
bacd、badc、bcad、bcda、bdca、bdac
cbad、cbda、cabd、cadb、cdab、cdba
dbca、dbac、dcba、dcab、dacb、dabc

 观察排列结果可知

a后面是bcd的全排列
b后面是cd的全排列
……

 即可以将题目分解几个不同规模的问题,原理如下图所示:
      https://www.cnblogs.com/nowornever-L/p/6008954.html图片来源

 即需要得到以a为开头的所有字母顺序时,求bcd的所有排列顺序即可,以此类推

核心代码分析
for(i = start;i <= end;i++){     //for循环为核心代码
			SWAP(list[start],list[i],temp);  //交换list[start]和list[i]的值
			perm(list,start + 1,end);        //进行递归,start+1表示求剩下字母的所有排列顺序
			SWAP(list[start],list[i],temp);  //还原字母顺序
}

 函数SWAP(x,y,t)为宏定义,用于交换x和y的值。
 核心代码中含有两个SWAP(x,y,z),且分别在递归调用前和递归调用后。

第一个SWAP(x,y,z)

就拿递归中第一层来说,因为执行到该语句时,已经完成以x为开头的所有字母序列的打印,所以需要置换新的字母作字母序列的首字母。相应得,x就需要参与首字母后面的几个字母的排列。
例如完成已经打印所有以a为首字母的序列时

abcd、abdc、acbd、acdb、adcb、adbc

就需要将a和b置换过来,使得a和c、d按照不同顺序排成字母序列连接在b后面,生成以b为首字母的所有字母序列

bacd、badc、bcad、bcda、bdca、bdac

第二个SWAP(x,y,z)

简单来说就是还原字母顺序,使得第一个SWAP(x,y,z)每次置换的结果是使得全排列结果的所有字母序列的首字母是按照原数组中字母顺序排列的。
例如原数组中字母顺序为:a、b、c、d
那么全排列的结果顺序应该为:

abcd、abdc、acbd、acdb、adcb、adbc
bacd、badc、bcad、bcda、bdca、bdac
cbad、cbda、cabd、cadb、cdab、cdba
dbca、dbac、dcba、dcab、dacb、dabc

C++代码
/*将字母按照全排列顺序打印*/
#include <iostream>
#define SWAP(x,y,t)((t) = (x),(x) = (y),(y) = (t))    //用于交换两个变量的值

using namespace std;
void perm(char list[],int start,int end){
	int i;
	char temp;
	if(start == end){
		for(i = 0;i <= end;i++)
			cout<<list[i];
		cout<<endl;
	}
	else{
		for(i = start;i <= end;i++){     //for循环为核心代码
			SWAP(list[start],list[i],temp);  //以已作为首字母出现的字母移动到后面
			perm(list,start + 1,end);
			SWAP(list[start],list[i],temp);  //还原字母顺序
		}
	}
}

int main(){
	char list[4] = {'a','b','c','d'};
	
	perm(list,0,3);
	return 0;
}

参考书籍:《数据结构基础》(C语言版)

### 字符串或数组的全排列算法实现 #### 使用 C# 实现字符串的全排列 在 C# 中,可以通过递归的方式实现字符串的全排列。以下是具体的代码示例: ```csharp using System; using System.Collections.Generic; public class Program { public static List<string> Permutations = new List<string>(); public static void GeneratePermutations(string prefix, string remaining) { int n = remaining.Length; if (n == 0) { Permutations.Add(prefix); } else { for (int i = 0; i < n; i++) GeneratePermutations(prefix + remaining[i], remaining.Substring(0, i) + remaining.Substring(i + 1, n - i - 1)); } } public static void Main() { string input = "abc"; GeneratePermutations("", input); Console.WriteLine("All permutations of the string:"); foreach (string permutation in Permutations) { Console.WriteLine(permutation); } } } ``` 这段代码通过递归调用 `GeneratePermutations` 函数来生成输入字符串的所有可能排列[^1]。 --- #### 使用 C++ 实现字符串的全排列 对于 C++ 的实现方式,可以采用类似的递归逻辑。以下是一个完整的例子: ```cpp #include <iostream> #include <vector> #include <algorithm> void permute(std::string str, int l, int r, std::vector<std::string>& result) { if (l == r) { result.push_back(str); } else { for (int i = l; i <= r; ++i) { std::swap(str[l], str[i]); permute(str, l + 1, r, result); std::swap(str[l], str[i]); // backtrack } } } std::vector<std::string> generate_permutations(const char* str) { std::vector<std::string> result; std::string s(str); permute(s, 0, s.length() - 1, result); return result; } int main() { const char* input = "abc"; std::vector<std::string> permutations = generate_permutations(input); std::cout << "All permutations of the string:\n"; for (const auto& p : permutations) { std::cout << p << "\n"; } return 0; } ``` 这里利用了交换字符的位置并回溯的方式来生成所有的排列组合[^2]。 --- #### 使用 JavaScript 实现数组的全排列 JavaScript 可以通过递归和循环相结合的方法轻松完成这一任务。下面是一段用于生成数组全排列的代码: ```javascript function getPermutations(array) { let results = []; function swap(arr, indexA, indexB) { let temp = arr[indexA]; arr[indexA] = arr[indexB]; arr[indexB] = temp; } function generate(n, heapArray) { if (n === 1) { results.push(heapArray.slice()); return; } generate(n - 1, heapArray); for (let i = 0; i < n - 1; i++) { if (n % 2 === 0) { swap(heapArray, i, n - 1); } else { swap(heapArray, 0, n - 1); } generate(n - 1, heapArray); } } generate(array.length, array.slice()); return results; } // Example usage: console.log(getPermutations([1, 2, 3])); ``` 此代码片段展示了如何通过对数组元素进行交换以及递归调用来获取所有可能的排列[^3]。 --- #### 关于字典序的理解 如果需要按照字典序输出排列结果,则可以在每次生成新的排列时对其进行比较,并按升序存储最终的结果集合。例如,在 Python 中可借助内置排序工具对列表进行处理后再返回结果[^4]。 --- #### Java 基于递归与回溯的解决方案 Java 提供了一种优雅而直观的方法来解决问题——即基于递归与回溯技术构建解空间树结构。这种方法能够有效地枚举出每一个合法状态直至找到目标答案为止[^5]。 ```java import java.util.ArrayList; import java.util.List; public class Solution { private List<String> res = new ArrayList<>(); public List<String> permute(String s){ boolean[] used = new boolean[s.length()]; StringBuilder path = new StringBuilder(); backtracking(s.toCharArray(),path,used); return res; } private void backtracking(char[] chs,StringBuilder path,boolean[] used){ if(path.length()==chs.length){ res.add(path.toString()); return ; } for(int i=0;i<chs.length;i++){ if(!used[i]){ used[i]=true; path.append(chs[i]); backtracking(chs,path,used); path.deleteCharAt(path.length()-1); used[i]=false; } } } public static void main(String[] args){ String test="abc"; Solution sol=new Solution(); System.out.println(sol.permute(test)); } } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值