/// <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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
计算阶乘的递归算法,后续会用到,虽然用了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[n];
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
计算排列数,主要思想是类似于小学数学中求分式相乘中的消除法,主要是为了避免求阶乘的限制
/// <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[n]; 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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
计算组合数,思路和求排列数一致,不再赘述
/// <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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
求所有可能的组合形式,一个递归实现,依次选择待组合元素中的前n-m个元素,每次选择后在剩下的元素中选取m-1个元素,直到m==1或者列表元素个数等于m则停止递归