摘要:[C#] 組合數學 (未完成)
///
/// 提供進階的數學方法。
///
public class jsMath
{
///
/// 計算n階乘的方法。
///
///
不為負數的整數
public static uint Factorial(uint n, uint startN = 2)
{
// 0! = 1 (這是定義),所以最少也就是1。
uint result = 1;
// i = 2 是因為 1*1 還是等於1,所以省略從1開始。
for (uint i = startN; i <= n; i++)
result *= i;
return result;
}
///
/// 計算n種取k種的排列數。
///
public static uint Permutation(uint n, uint k)
{
return Factorial(n, (n - k) +1);
//return Factorial(n) / Factorial(n - k); // 公式: http://zh.wikipedia.org/wiki/%E7%B5%84%E5%90%88%E6%95%B8%E5%AD%B8
}
///
/// 計算n種取k種的組合數。
///
public static uint Combination(uint n, uint k)
{
return Permutation(n, k) / Factorial(k); // 公式: http://zh.wikipedia.org/wiki/%E7%B5%84%E5%90%88%E6%95%B8%E5%AD%B8
}
}
///
/// 產生泛型的組合數學陣列結果。
///
///
public class Combination
{
///
/// 自定義形態清單表。
///
public T[] arrAll { get; private set; }
///
/// 要取得的數量。
///
public uint kSize { get; private set; }
///
/// 旋轉的總次數。
///
public uint totalRotateLength { get; private set; }
///
/// 目前旋轉的索引。
///
public uint curRotateIndex { get; private set; }
///
/// 是否已取得完畢?
///
public bool HasGetsEnd { get { return curRotateIndex >= this.totalRotateLength; } }
///
/// 初始化n清單與要取得的k大小。
///
public Combination(ref T[] arrT, uint kSize)
{
this.arrAll = arrT;
this.kSize = kSize;
uint n = (uint)arrAll.Length;
uint k = kSize;
if (n < k) throw new Exception();
this.totalRotateLength = jsMath.Combination(n, k);
this.curRotateIndex = 0;
}
///
/// 取得下一個旋轉後的組合結果。
///
public T[] GetNextRotateResult()
{
// 取得目前次數的旋轉索引偏移陣列値。
uint[] arrRotateIndexOffset = GetCurrentIndexOffset();
T[] arrPartial = new T[arrRotateIndexOffset.Length];
// 從旋轉的索引表數值對應到清單表中的數值複製k個出來。
for (int i = 0; i < arrRotateIndexOffset.Length; i++)
arrPartial[i] = arrAll[arrRotateIndexOffset[i]];
// 取得後,遞增為下一個索引値。
this.curRotateIndex++;
return arrPartial;
}
///
/// 取得目前次數的旋轉索引偏移陣列値。
///
protected uint[] GetCurrentIndexOffset()
{
uint[] arrRotateIndexOffset = new uint[kSize];
// 第一個索引固定不動,
arrRotateIndexOffset[0] = (uint)(this.curRotateIndex % arrAll.Length);
// 由第二個索引値開始往右移動,可以保持不重複的組合。
for (uint i = 1; i < arrRotateIndexOffset.Length; i++)
{
uint value = (uint)(arrRotateIndexOffset[0] + i + this.curRotateIndex / arrAll.Length);
arrRotateIndexOffset[i] = value < arrAll.Length ? value : value - (uint)arrAll.Length;
}
return arrRotateIndexOffset;
}
}