动机

Apache Math包中有很多关分布的算法,但是没有找到排列组合相关的算法。索性自己写一个。排列组合可以分两个算法:

  1. 组合算法,就是在一个数组中取出m(小于等于数组的长度 n)个对象,有多少中不同的取法。不考虑重复元素,组合数应该为 n! / m! / (n-m)! 。
  2. 排列算法,给定一个数据,对这个数组进行排列。如果不考虑相同的元素,排列数应该式n!(n为数组长度),但是算法中需要考虑相同的元素。

算法

排列算法

在前面的算24点文章用到了排列的算法。排列算法如果用递归实现还是比较容易的,但是考虑到效率的问题算法用回溯法来实现,算法中引入一个消费者方法来处理一个排列,这样避免返回很大的数组,n!是一个很大的数。

public static <T> void permutation(List<T> listSouce ,Comparator<? super T> comparable,Consumer<List<T>> consumer){int len = listSouce.size();if(len<2){consumer.accept(listSouce);return;}listSouce.sort(comparable);//标记排序位置的栈List<Integer> comPos = new ArrayList<>(len);//标记已经排好序的元素List<Boolean> usedItem = new ArrayList<>(len);//记录排序结果List<T> comRes = new ArrayList<>(len);for(int i=0;i<len;i++){comPos.add(-1);usedItem.add(false);comRes.add(null);}comPos.set(0,0);int sortIndex = 0;usedItem.set(0, true);while(sortIndex >=0 ){comRes.set(sortIndex, listSouce.get( comPos.get(sortIndex)));if( sortIndex == len - 2){ // 如果获得一个排序for(int i=0; i< len; i++){if(!usedItem.get(i)){// 将最后一个未使用的添加到排列的最后comRes.set( sortIndex +1, listSouce.get(i));break;}}consumer.accept(comRes);//usedItem.set(comPos.get(sortIndex), false);while(sortIndex >=0 ) {//下一个int prePos = comPos.get(sortIndex);usedItem.set(prePos, false);//当前pos ++ (步进)while (comPos.get(sortIndex) + 1  < len &&( usedItem.get(comPos.get(sortIndex) + 1) || comparable.compare(listSouce.get(prePos),listSouce.get(comPos.get(sortIndex) + 1)) == 0 )) {comPos.set(sortIndex, comPos.get(sortIndex) + 1);}comPos.set(sortIndex, comPos.get(sortIndex) + 1);// 如果已经到上线,继续回退if (comPos.get(sortIndex)  < len ) {//重新计算下个列表usedItem.set(comPos.get(sortIndex), true);comRes.set( sortIndex, listSouce.get(comPos.get(sortIndex)));break;}else{ // 回退sortIndex--;//comPos.set(sortIndex, comPos.get(sortIndex) + 1);}}} else { // 下一个for(int i=0; i< len; i++){if(!usedItem.get(i)){comPos.set(sortIndex + 1,i);usedItem.set(i,true);break;}}sortIndex++;}}}

组合算法

组合算法比排列简单一点,重点式考虑重复元素的问题,和排列一样,先对数组进行排序。同样引入一个消费者方法来处理一个给点的组合,组合也是一个很大的数,不能直接返回数组。

 public static <T> void combination(List<T> listSouce , int selected,Comparator<? super T> comparable,Consumer<List<T>> consumer) {int len = listSouce.size();if(len<selected || selected < 1){return;}if(len == selected){consumer.accept(listSouce);return;}listSouce.sort(comparable);//标记排序位置的栈List<Integer> selectPos = new ArrayList<>(selected);List<T> comRes = new ArrayList<>(selected);for(int i=0;i<selected;i++){selectPos.add(i);comRes.add(listSouce.get(i));}int sortIndex = selected-1;while(sortIndex >= 0){if(sortIndex == selected-1){consumer.accept(comRes);}while(selectPos.get(sortIndex) + 1  < len && comparable.compare(listSouce.get(selectPos.get(sortIndex)),listSouce.get(selectPos.get(sortIndex) + 1))==0){selectPos.set(sortIndex, selectPos.get(sortIndex)+1);}selectPos.set(sortIndex, selectPos.get(sortIndex)+1);if (selectPos.get(sortIndex)  <= len - selected + sortIndex ) {//重新计算下个列表comRes.set(sortIndex, listSouce.get( selectPos.get(sortIndex)));int startPos = selectPos.get(sortIndex) +1;for(int i = sortIndex+1 ; i < selected; i++) {selectPos.set(i, startPos);comRes.set(i, listSouce.get(startPos));startPos ++;}sortIndex = selected-1;//continue;}else{ // 回退sortIndex--;//comPos.set(sortIndex, comPos.get(sortIndex) + 1);}}}

排列与组合

排列组合就是简单对两个方法整合一下。

public static <T> void permutationAndCombination(List<T> listSouce , int selected,Comparator<? super T> comparable,Consumer<List<T>> consumer) {combination(listSouce , selected, comparable,( oneCom ) -> permutation(oneCom, comparable,  consumer));}

测试代码

public class MathOpt {//将 数字和操作排序public static void sortFormulaOpt( List<Integer> rList ){for(Integer i : rList){System.out.print(i);System.out.print(" ");}System.out.println();}public static void main(String arg[]) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));while (true) {System.out.println("输入用空格隔开整数,推出输入exit");String s = br.readLine().trim();if(StringUtils.isBlank(s)){continue;}if(StringUtils.equalsIgnoreCase("exit",s)){break;}int nSelect = -1;String[] nums = s.split(" ");List<Integer> alist = new ArrayList<>(4);for(int i=0; i<nums.length; i++){if(StringRegularOpt.isNumber(nums[i])){if( nSelect == -1 ){nSelect = NumberBaseOpt.castObjectToInteger(nums[i]);}else {alist.add(NumberBaseOpt.castObjectToInteger(nums[i]));}}}if( alist.size() < 1){continue;}Mathematics.permutationAndCombination(alist,nSelect, Integer::compare, MathOpt::sortFormulaOpt);}}
}

源码

排列组合相关的源码;更多南大先腾开源项目参见https://ndxt.github.io/。

通用的非递归排列和组合算法[附源码]相关推荐

  1. C语言常用13种算法附源码

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105147802 常 ...

  2. java 实现组合_用Java实现排列、组合算法

    组合个数的计算公式如下: 那么,计算排列或组合的数量,通过上面的公式就很容易就算出来了,其Java的实现如下: /** * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 * ...

  3. 非递归遍历二叉树(算法导论第三版第十章10.4-5)

    非递归遍历二叉树(算法导论第三版第十章10.4-5) template<typename T> void TraverseBinaryTreeNonRecursive(BinaryTree ...

  4. 二叉树非递归后序遍历算法

    与正常的非递归中序遍历算法不同于两点: 一  比正常的中序遍历算法多了对数据元素的标记. 在压数据元素入栈(标记记为0,用来表示访问了其左子树)时标记, 还有访问完左子树利用gettop()获取双亲通 ...

  5. 【Java数据结构与算法】第十七章 二分查找(非递归)和分治算法(汉诺塔)

    第十七章 二分查找(非递归)和分治算法(汉诺塔) 文章目录 第十七章 二分查找(非递归)和分治算法(汉诺塔) 一.二分查找 1.思路 2.代码实现 二.分治算法(汉诺塔) 1.概述 2.汉诺塔 一.二 ...

  6. c语言栈的实现以及操作_python模拟栈的操作实现非递归方式的快速排序算法

    本文首发地址: https://yishuihancheng.blog.csdn.net/article/details/76185032 欢迎关注我的博客[Together_CZ],我是沂水寒城! ...

  7. java排列和组合算法

    package com.louisgeek.price;/*** 排列和组合算法* @author Administrator**/ public class CaseTest {public sta ...

  8. 二叉树非递归后序遍历算法的一种简单思路

    首先从简单的例子开始 1 2 3 上图二叉树的后序遍历序列是"231", 颠倒一下就是"132", 而其前序遍历是"123" 有什么发现? ...

  9. 二叉树非递归后序遍历算法(C语言)

    二叉树非递归后序遍历算法(C语言) 二叉树后序遍历的规律:左右根 后序非递归遍历中,访问根(子根)结点有两种情况 ①:遍历完左子树,需要遍历右子树,需要从栈中访问最顶上的根(子根)结点从而得到右子树的 ...

最新文章

  1. 企业名片小程序时代,打破纸质名片局限!
  2. 实战:将静态路由发布到动态路由
  3. ubuntu 终端常用命令
  4. 凑微分公式_武忠祥真题班归纳(更新至多元函数微分学)
  5. 求助!C++ 实践之引入外部头文件失败
  6. python中类的定义和使用_在Python中定义和使用类
  7. 智能优化算法:供需优化算法-附代码
  8. Ubuntu 安装arm-linux-gcc编译器
  9. 渗透测试web安全 - webshell 免杀 绕过waf总结
  10. 【win11】你不能不会的技巧(持续更新)
  11. 香槟分校计算机研究生专业,伊利诺伊大学香槟分校计算机科学专业各大方向介绍...
  12. linux下回收站无法清空 解决
  13. 微信小程序实现登录获取头像昵称
  14. 整除判断游戏能显著提高小朋友的逻辑思维能力,问题要求如下:• 能同时被 3、5、7 整除• 能同时被 3、5 整除• 能同时被 3、7 整除• 能同时被 5、7 整除• 只能被 3、5、7
  15. 【Unity】Mesh网格编程(三)万能网格几何形体
  16. Q Inventory System unity背包物品插件 使用笔记
  17. 神经网络与深度学习笔记汇总二
  18. VirtualBox for macOS NS_ERROR_FAILURE (0x80004005) 问题解决记录
  19. 《Python编程从入门到实践》学习笔记9:类
  20. 一元夺宝项目设计(上)

热门文章

  1. 2017年终总结(小巫)
  2. 周志华西瓜书 10 个算法详细视频
  3. 如何判断excel一个单元格中的内容是否有重复的括号
  4. su 命令和sudo命令的区别
  5. 解决word大纲工具栏的设置问题
  6. 五大UNIX系统家族族谱
  7. 【高级数据库】第三章 查询执行
  8. 三方流通平台:中国大数据区块链开启web5.0时代
  9. SQL Server 常用更新语句,用B表数据作为条件或数据源更新A表数据
  10. Android:手机关闭相机拍照声音