假定你有四個姓名條目——Adam, Barb, Carl, Dave——你想得到所有這四個條目中每次選出兩個元素的組合。下面所示的 C# 代碼片斷將生成這個組合的六個元素:
// naive technique to generate all combinations Console.WriteLine("\nAll elements of 4 names, 2 at a time: "); string[] names = {"Adam", "Barb", "Carl", "Dave"}; for (int i = 0; i < names.Length; ++i) { for (int j = i+1; j < names.Length; ++j) { Console.WriteLine( "{ " + names[i] + ", " + names[j] + " }" ); } }
如果你執行這個代碼,(正確的)結果將是:
{ Adam, Barb }, { Adam, Carl }, { Adam, Dave }, { Barb, Carl },
{ Barb, Dave }, { Carl, Dave }.
但是這里有三個問題。首先,如果你想要生成組合的所有元素時,這個方法運行很正常,但是如果你只想得到部分元素或一個特別元素呢?第二,這是一個對于特定問題的特定 解法,它并不具有普遍性。第三,只有當每個子集元素的條目個數 k 很小時,它才能工作得較好。
但是如果 k 非常大時會怎樣呢?如果你想一次從 n = 100 個的條目中挑出 50 個,你就不得不編寫50個循環或使用遞歸。
對于生成所有組合元素的一個更好的解決方案是實現一個 Successor(繼承)方法,它返回給定元素的下一個按詞典排序的元素。如果你將 Successor 和 ApplyTo 方法聯合使用,它 將某個數學組合映射到一個字符數組上,你將會具備一個有效的、具有普遍性的方法來生成所有組合元素。
Figure 6 的代碼表示了 Successor 方法。Successor 一開始就檢查這里是否存在下一個組合元素。舉個例子,假設你正在處理每次從 n=5 個條目中取 k=3 個元素。這里 有 10 種組合情況:
{ 0, 1, 2 } { 0, 3, 4 }
{ 0, 1, 3 } { 1, 2, 3 }
{ 0, 1, 4 } { 1, 2, 4 }
{ 0, 2, 3 } { 1, 3, 4 }
{ 0, 2, 4 } { 2, 3, 4 }
注意你可以確定詞典序列的最后一個元素,{ 2, 3, 4 },因為這里只有一個元素它有第一個原子2——它等于 n-k 的值,或者換句話說,它有一個 n-k 的值在第0個位置上。這個關系一般來說對于所有的組合都是正確的。同樣地,你可以確定詞典序列的第一個元素,{ 0, 1, 2 },因為這里只有一個元素的最后一個原子為 2,或者換句話說,這里有 n-k 的值在第 k-1 位置上。而且,一般來說這總是正確的。如果這里沒有有效的下一個元素 Successor 方法就返回 null。選擇返回 null 將導致拋出一個異;蚍祷匾粋錯誤代碼。
文章來源于領測軟件測試網 http://www.kjueaiud.com/