代码改变世界

[续]全排列的非递归实现

  coodoing  阅读(890)  评论(0编辑  收藏  举报

       前文提到过全排列的递归实现,这里在简单的介绍下全排列的非递归实现。

        以6个数字的全排列为例说明,相当于用1,2,3,4,5,6 构造一个六位数,每一位上取一个数,这样一共有6!中方法。
很显然,这6!个数是有大小的,如果按从小到大排列,示意如下:
1 2 3 4 5 6
1 2 3 4 6 5
1 2 3 5 4 6
…………
6 5 4 3 2 1
     显然 , 每个数有唯一后继 ! 如果找到一个数没有后继(6 5 4 3 2 1),则停止。

     那么问题的重点在于如何判断是否有后继,以及怎样找到后继 !  是否有后继很好判断,唯一没有后继的只有654321,它的特点是每位的数字比后面的大!如何找到后继,思路很清楚,即对于一个数,找到一个比它大的、最小的数!

     来考虑"926510"这个字符串,我们从后向前找第一双相邻的递增数字,"10"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后往前找一个比替换数大的最小数(这个数必然存在),0、1都不行,5可以,将5和2交换得到"956210",然后再将替换点后的字符串"6220"颠倒即得到"950226"。同理:比如926540的后继应该是946520,而不是956240。

   1: public class NonRecursivePermutation {
   2:  
   3:     static int[] arr = new int[] { 1, 2, 3, 4, 5, 6 };
   4:     static int count = 1;
   5:  
   6:     // 反转区间
   7:     private static void reverse(int[] arr, int pBegin, int pEnd) {
   8:         while (pBegin < pEnd)
   9:             swap(arr, pBegin++, pEnd--);
  10:     }
  11:  
  12:     private static void swap(int[] arr, int i, int j) {
  13:         int temp;
  14:         temp = arr[i];
  15:         arr[i] = arr[j];
  16:         arr[j] = temp;
  17:     }
  18:  
  19:     private static boolean hasNext() {
  20:         for (int i = arr.length - 1; i > 0; i--) {
  21:             if (arr[i] > arr[i - 1])
  22:                 return true;
  23:         }
  24:         return false;
  25:     }
  26:  
  27:     private static void next() {
  28:         int len = arr.length;
  29:         int replace = 0; // 需替换数
  30:         int firstR = 0; // 从后向前找比替换数大的第一个数
  31:         // 找降序的相邻2数,前一个数即需替换数
  32:         for (int i = len - 1; i > 0; i--) {
  33:             if (arr[i] > arr[i - 1]) {
  34:                 replace = i - 1;
  35:                 break;
  36:             }
  37:         }
  38:         
  39:         //System.out.println("需替换数位置:" + replace);
  40:         
  41:         // 从后向前找比替换数大的第一个数
  42:         // 比如926540的后继应该是946520,而不是956240
  43:         for (int i = len - 1; i > replace; i--) {
  44:             if (arr[i] > arr[replace]) {
  45:                 firstR = i;
  46:                 break; //找到之后直接退出
  47:             }
  48:         }
  49:         
  50:         //System.out.println("替换数位置:" + firstR);
  51:         
  52:         // replace与firstR交换
  53:         swap(arr, replace, firstR);
  54:         // 替换数后的数全部反转
  55:         reverse(arr, replace + 1, len - 1);
  56:  
  57:         count++;
  58:         print();
  59:     }
  60:  
  61:     private static void print() {
  62:         for (int i = 0; i < arr.length; i++)
  63:             System.out.print(arr[i] + " ");
  64:         System.out.println();
  65:     }
  66:  
  67:     /**
  68:      * @param args
  69:      */
  70:     public static void main(String[] args) {
  71:  
  72:         while (hasNext() == true) {
  73:             next();
  74:         }
  75:         System.out.println("数组完全反转后的结果:");
  76:         reverse(arr, 0, arr.length - 1);
  77:         print();
  78:         System.out.println("全排列的数目为:" + count);
  79:  
  80:         /*********************/
  81:         System.out.println("数组是否存在后继:" + hasNext());
  82:         System.out.println("数组一次替换后的结果:");
  83:         next();
  84:     }
  85:  
  86: }

  除了上述的找后继实现外,还有一种基于变进制数的实现。这里可以用来作为一个参考。

  最后附加利用python中itertool模块求全排列的简短代码。

import itertools
list(itertools.permutations([1,2,3]))
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示