
本文详解为何原四层 while 循环仅输出 14 行结果,并提供两种可靠解决方案:修复嵌套重置逻辑,以及用单循环+模运算高效生成全部 14⁴ = 38416 种组合。
你遇到的问题并非逻辑错误,而是变量状态未重置导致的循环提前终止。原始代码中,moveSet[1]、moveSet[2] 和 moveSet[3] 在首次内层循环结束后持续保持为 14(即超出
✅ 正确做法:每次进入更外层循环前,显式将所有内层计数器重置为 0:
public static void iterateThroughMoves() {
byte[] moveSet = {0, 0, 0, 0};
while (moveSet[0] < 14) {
moveSet[1] = 0; // ← 关键:重置第2位
while (moveSet[1] < 14) {
moveSet[2] = 0; // ← 关键:重置第3位
while (moveSet[2] < 14) {
moveSet[3] = 0; // ← 关键:重置第4位
while (moveSet[3] < 14) {
System.out.println(Arrays.toString(moveSet));
moveSet[3]++;
}
moveSet[2]++;
}
moveSet[1]++;
}
moveSet[0]++;
}
}⚠️ 注意事项:
- byte 类型范围是 -128 ~ 127,14 完全安全,但若将来扩展上限(如 ≥ 128),需改用 int 或显式类型转换;
- 上述修复后总迭代次数为 14 × 14 × 14 × 14 = 38,416,符合预期;
- 嵌套过深(尤其 ≥ 4 层)易出错且难维护,推荐更通用的替代方案。
? 更优雅的解法:使用单层 for 循环 + 进制分解思想。将四维组合视为「14 进制」的 4 位数,从 0 到 14⁴−1 编号,再逐位取模还原:
public static void iterateThroughMovesOptimized() {
int total = 14 * 14 * 14 * 14; // 38416
for (int i = 0; i < total; i++) {
byte[] moveSet = new byte[4];
moveSet[3] = (byte) (i % 14); // 个位(最低位)
moveSet[2] = (byte) ((i / 14) % 14); // 十位
moveSet[1] = (byte) ((i / 14 / 14) % 14); // 百位
moveSet[0] = (byte) ((i / 14 / 14 / 14) % 14); // 千位(最高位)
System.out.println(Arrays.toString(moveSet));
}
}该方法优势明显:
✔️ 无嵌套,逻辑清晰,易于扩展(如改为 5 位只需增加一行);
✔️ 避免手动重置错误;
✔️ 时间复杂度相同,但常数开销更低(无重复赋值);
✔️ 天然支持并行化(如 IntStream.range(0, total).parallel().forEach(...))。
总结:嵌套循环必须严格管理各层变量的生命周期——外层推进时,内层应“归零重启”。而对固定基数的全排列问题,进制映射法是更健壮、可扩展的工程实践。










