#<center>基於C#程序設計語言的三種組合算法</center>算法
[TOC]數組
##1. 整體思路 ###1.1 前言spa
最近有個項目要求對多種材料進行裝箱,我須要給出裝箱的可能,這些材料進行過度組,每組中大體選取2-3個材料進行裝箱。因爲沒法得知箱子大小(沒法對組合數的m進行限制),材料會擴充,隨之分組也會擴充(沒法對組合數的n進行限制),因此理論上說能產生的組合是無限的,這固然沒法實現,但咱們仍是能經過用戶的輸入來進行最大可能的處理。設計
###1.2 算法思路指針
組合算法思路是比較簡單的(如下全部數據均可以想象成string[]
類型的),獲取源數據S
,C(1,n)的結果S1
,將S
的每一個元素與S1
進行相應組合獲得C(2,n)的結果S2
(思路演示見圖1.2.1),S2
,將S
的每一個元素與S2
進行相應組合,獲得S3
...重複這個過程獲得Sn
。code
S
的元素與Si
進行組合的方式不一樣得到的組合結果不一樣,若是和元素自己進行了組合,組合結果就包括了與自身組合。 blog
<center><font size=2>圖1.1 C(2, n)組合過程</font></center>遞歸
###1.3 算法須要注意的點索引
雖然思路比較簡單,可是處理起來仍是有些地方須要注意。在每次進行組合時,須要對Si
進行去頭處理。內存
去頭處理:去掉Si
中不能與S[i]
組合的元素
在不一樣的組合中去掉的頭也不一樣。在與S1
組合時,每次去掉的只有一組元素[A],[B],[C],[D],[E]
,但在與S2
組合時,去掉的頭分別是:[A,B],[A,C],[A,D],[A,E]
(4組),[B,C],[B,D],[B,E]
(3組),[C,D],[C,E]
(2組),[D,E]
(1組)。推過推演能夠發現,這組數據是有規律的,根據1.2,1.3小節總結出來的規律,大體能夠構建出組合算法了。
##2. 三種組合算法 ###2.1 普通組合算法
在第1章已經介紹了普通組合算法的思路,這裏主要說明如何用C#代碼來處理組合運算,首先須要定義三個List<string>
類型src
,res
,tmp
,src
用來存儲須要進行組合處理的源數據,res
用來存儲組合處理後的數據,tmp
用來存儲在操做過程當中的臨時數據。定義一個int[] rm
變量用來存儲每次須要去頭的個數(例如src=[A,B,C,D,E],進行第一次組合時,rm = [1,1,1,1], 進行第二次組合時,rm = [4,3,2,1])。
string[] Combination(List<string> src, List<string> res, List<string> tmp, ref int[] rm, int rsp, int tmp_index, int rp) { if(res.Count() == 0) { return tmp; } if(rsp == res.Count()) { src.Removerange(0, 1); res.Removerange(0, rm[rp]); rm[rp] = rsp; rsp = 0; rp += 1; } tmp[tmp_index] = src[0] + "," + res[rsp]; tmp = Combination(src, res, tmp, rm, rsp + 1, tmp_index + 1, rp); return tmp; }
<center><font size=2>代碼清單2.1 普通組合算法</font></center>
###2.2 與自身進行組合的組合算法
本節思路及代碼與2.1小節大同小異,故先略過。
###2.3 組合元素進行過度組限制的組合算法
如今要求將元素進行分組,每組的元素個數隨機,從每組最多選擇x個元素進行組合。這種算法只須要在普通組合算法程序中進行一些條件限制即可以實現,最主要須要注意的問題是,rm
中存儲的數據不一樣了(對下次去掉的頭有了限制)。因爲rm[rp]
再也不是rsp
了,因此須要新的變量count
來計算下次須要去掉的頭。
string[] Combination(List<string> src, List<string> res, List<string> tmp, ref int[] rm, int rsp, int tmp_index, int rp, int count) { if(res.Count() == 0) { return tmp; } if(rsp == res.Count()) { src.Removerange(0, 1); res.Removerange(0, rm[rp]); rm[rp] = count; rsp = 0; rp += 1; } // ... // 檢測是否屬於同一分組,若是屬於同一分組,則bool bl = true; // ... if(bl == true) tmp = Combination(src, res, tmp, rm, rsp + 1, tmp_index + 1, rp); else { tmp[tmp_index] = src[0] + "," + res[rsp]; count++; } return tmp; }
<center><font size=2>代碼清單2.2 有分組限制的組合算法</font></center>
代碼清單2.2中,省略了「檢測是否屬於同一分組」的代碼,由於不一樣需求的初始條件不同,故略過了此段代碼。在我涉及到的需求中,我是將分組內容用DataTable
存儲,而後「檢測同一分組」時會去表中檢索,以此來判斷是否屬於同一分組。對於檢測,我將所須要檢測的內容組合成一個數組,而後檢測首元素是否與指向元素屬於同一分組,若是屬於,bool bl
爲true
,若是不屬於,則爲false
。
我將所須要檢測的內容組合成一個數組,而後定義兩個指針(索引)pa
,pb
,pa
與pb
初始都指向首元素,若pa
內容與pb
內容相等,則count++
,若pa
內容與pb
內容不等,則pa = pb + 1
,再重複上述步驟,這樣能夠統計出一個組內包含多少個成員。
##3. 請使用循環替代遞歸
最後,請使用循環來帶起遞歸過程,由於遞歸未結束時,是不會釋放內存的,在數據量大時,會形成內存溢出的錯誤,因此,請使用循環。