
本文详解如何使用递归算法生成字符数组的所有排列,基于 heap’s algorithm 实现高效、无重复的全排列,并提供可运行的 java 代码、关键逻辑解析与注意事项。
在 Java 中实现字符数组的全排列,核心在于设计一个正确、通用且无遗漏的递归策略。题中示例要求对 {'a','b','c','d'} 生成所有排列(共 4! = 24 种),但原始代码仅做简单交换,无法覆盖全部组合,也未体现递归回溯的本质。正确的解法应采用经典的 Heap’s Algorithm——它时间复杂度最优(O(n!))、空间原地、且天然支持递归实现。
该算法的关键思想是:
- 对长度为 n 的数组,先递归生成前 n−1 个元素的全排列;
- 然后根据 n 的奇偶性,决定如何交换第 n 个元素(索引 n−1)与哪个位置的元素:
- 若 n 为奇数 → 总是交换首元素(索引 0)与末元素(索引 n−1);
- 若 n 为偶数 → 每轮迭代 i(从 0 到 n−1)时,交换索引 i 与 n−1 处的元素。
以下是完整、可直接运行的实现:
public class Main2 {
public static void main(String[] args) {
char[] charArray = {'a', 'b', 'c', 'd'};
permute(charArray, charArray.length);
}
public static void permute(char[] a, int lengthOfa) {
// 基础情况:只剩一个元素时,输出当前排列
if (lengthOfa == 1) {
printArray(a, a.length);
return;
}
// 递归处理前 lengthOfa-1 个元素的所有排列
for (int i = 0; i < lengthOfa; i++) {
permute(a, lengthOfa - 1);
// 根据 lengthOfa 的奇偶性执行对应交换(关键步骤)
if (lengthOfa % 2 == 1) {
// 奇数长度:固定交换首尾
swap(a, 0, lengthOfa - 1);
} else {
// 偶数长度:每次交换第 i 个与末位
swap(a, i, lengthOfa - 1);
}
}
}
private static void swap(char[] a, int i, int j) {
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
private static void printArray(char[] a, int n) {
for (int i = 0; i < n; i++) {
System.out.print(a[i]);
if (i < n - 1) System.out.print(" ");
}
System.out.println();
}
}✅ 运行效果:将输出全部 24 种排列(如 a b c d、b a c d、c b a d 等),顺序符合 Heap’s Algorithm 的标准生成路径。
立即学习“Java免费学习笔记(深入)”;
⚠️ 注意事项:
- 不要直接修改 lengthOfa 为硬编码值(如 4),必须保持参数动态,以支持任意长度数组;
- swap 方法封装提升可读性与复用性;
- 输出时建议传入 a.length 而非固定数字(如原答案中的 4),增强健壮性;
- 此算法不保证字典序,若需排序输出,应在生成后收集至 List
再调用 Collections.sort(); - 由于是原地交换,多线程环境下需加锁或改用不可变副本。
总结:掌握 Heap’s Algorithm 的递归结构,不仅解决了本题,更为理解回溯、排列生成及算法优化打下坚实基础。务必理解每次交换的触发条件与作用域,避免陷入“只换不回溯”的常见误区。










