C# 计算排列组合数,及列出所有组合形式的算法
2017-04-18 16:26
726 查看
前段时间有同学问到,如何编程求排列组合数,以及列出所有排列组合形式的算法。乘着放假,写了一种实现的方法!怕时间长了,淹没在硬盘里,记录在此!
计算阶乘的递归算法,后续会用到,虽然用了long类型,但也只能计算到20的阶乘
计算排列数,主要思想是类似于小学数学中求分式相乘中的消除法,主要是为了避免求阶乘的限制
计算组合数,思路和求排列数一致,不再赘述
求所有可能的组合形式,一个递归实现,依次选择待组合元素中的前n-m个元素,每次选择后在剩下的元素中选取m-1个元素,直到m==1或者列表元素个数等于m则停止递归
排列的所有形式可以在此基础上得到,但是还没有想到满意的算法!思考中……
PS:为了更明白的表达解题思路,算法没有做优化!
/// <summary> /// 计算Int32类型的整数的阶乘,目前最大只能对20以内的正整数求阶乘 /// </summary> /// <param name="n">Int32类型的正整数</param> /// <returns></returns> public static long Factor(this int n) { long result = -1; checked { try { if (n < 0) { result = -1; } else { if (n == 0 || n == 1) { result = 1; } else { result = n * (n - 1).Factor(); } } } catch (OverflowException) { result = -1; } } return result; }
计算阶乘的递归算法,后续会用到,虽然用了long类型,但也只能计算到20的阶乘
/// <summary> /// 计算从n个不同元素中任选m个元素的排列个数.n应该大于等于m! /// </summary> /// <param name="n">供排列选择的元素个数,正整数</param> /// <param name="m">排列选取的元素个数,正整数</param> /// <returns>排列个数</returns> public static long Permutation(int n,int m) { int[] N = new int ; int[] SubM = new int[n-m]; long result = 0; if (n < m) { result = 0; } else { //初始化数组N和M for (int i = 0; i < n; i++) { N[i] = i + 1; if (i < n - m) { SubM[i] = i + 1; } } //消除两个数组中的重复元素 for (int i = 0; i < n - m; i++) { if (SubM[i] == N[i]) { N[i] = 1; } } //计算N中剩余元素的累乘 result = 1; checked { try { for (int i = 0; i < n; i++) { result *= N[i]; } } catch (OverflowException) { result = -1; } } } return result; }
计算排列数,主要思想是类似于小学数学中求分式相乘中的消除法,主要是为了避免求阶乘的限制
/// <summary> /// 计算从n个不同元素中选取m个元素的组合个数。n应该大于等于m /// </summary> /// <param name="n">供组合选择的元素个数,正整数</param> /// <param name="m">组合选取的元素个数,正整数</param> /// <returns>组合个数</returns> public static long Combination(int n, int m) { long factM = m.Factor(); long result = 0; int[] N, M, subM; if (n < m) { result = 0; } else { if (factM > 0) { result = Permutation(n, m) / factM; } else { N = new int ; M = new int[m]; subM = new int[n - m]; //初始化三个数组 for (int i = 0; i < n; i++) { N[i] = i + 1; if (i < m) { M[i] = i + 1; } if (i < n - m) { subM[i] = i + 1; } } //消除重复元素,因为当m的阶乘溢出时才会进入此分支,所以只考虑和数组M进行消除 for(int i = 0; i < m; i++) { if (N[i] == M[i]) { N[i] = 1; } } //计算数组N和subM的累乘 long rN = 1, rSubM = 1; for (int i = 0; i < n; i++) { rN *= N[i]; if (i < n - m) { rSubM *= subM[i]; } } //计算组合个数 result = rN / rSubM; } } return result; }
计算组合数,思路和求排列数一致,不再赘述
/// <summary> /// 获得从n个不同元素中任意选取m个元素的组合的所有组合形式的列表 /// </summary> /// <param name="elements">供组合选择的元素</param> /// <param name="m">组合中选取的元素个数</param> /// <returns>返回一个包含列表的列表,包含的每一个列表就是每一种组合可能</returns> public static List<List<T>> GetCombinationList<T>(List<T> elements,int m) { List<List<T>> result = new List<List<T>>();//存放返回的列表 List<List<T>> temp = null; //临时存放从下一级递归调用中返回的结果 List<T> oneList = null; //存放每次选取的第一个元素构成的列表,当只需选取一个元素时,用来存放剩下的元素分别取其中一个构成的列表; T oneElment; //每次选取的元素 List<T> source = new List<T>(elements); //将传递进来的元素列表拷贝出来进行处理,防止后续步骤修改原始列表,造成递归返回后原始列表被修改; int n = 0; //待处理的元素个数 if (elements != null) { n = elements.Count; } if(n==m && m != 1)//n=m时只需将剩下的元素作为一个列表全部输出 { result.Add(source); return result; } if (m == 1) //只选取一个时,将列表中的元素依次列出 { foreach(T el in source) { oneList = new List<T>(); oneList.Add(el); result.Add(oneList); oneList = null; } return result; } for (int i = 0; i <= n - m; i++) { oneElment = source[0]; source.RemoveAt(0); temp = GetCombinationList(source, m - 1); for (int j = 0; j < temp.Count; j++) { oneList = new List<T>(); oneList.Add(oneElment); oneList.AddRange(temp[j]); result.Add(oneList); oneList = null; } } return result; }
求所有可能的组合形式,一个递归实现,依次选择待组合元素中的前n-m个元素,每次选择后在剩下的元素中选取m-1个元素,直到m==1或者列表元素个数等于m则停止递归
排列的所有形式可以在此基础上得到,但是还没有想到满意的算法!思考中……
PS:为了更明白的表达解题思路,算法没有做优化!
相关文章推荐
- 排列 组合 算法 C#
- C#实现排列组合算法
- 每日一省之————递归法计算数组的所有排列组合
- 从1..n中间选取任意组合,其和为m,列出所有组合的算法。
- [经典算法] 排列组合-N元素集合的所有子集(一)
- C#语法灵活运用之排列组合算法
- [算法]计算全排列组合数
- (C#)计算字符串排列组合数 如"abcd"组合数为24 "aabb"组合数为6
- C#查找字符串所有排列组合的方法
- C#实现排列组合算法完整实例
- 清华组合数学第一章经典复习题,用六种算法计算839647521后999种排列
- 排列组合-打印出一个数组的元素的所有排列方式-算法
- 基于C#的排列和组合算法
- N个数组中所有元素的排列组合(笛卡尔积)算法
- STL中计算排列组合关系的算法
- 列出多个数组所有排列组合
- [经典算法] 排列组合-N元素集合的所有子集(二)
- 黑马程序员-.NET-C#查找字符串的所有排列组合
- 全排列和组合算法的C#语言实现
- 从1..n中间选取任意组合,其和为m,列出所有组合的算法。