未知深度的巢狀迴圈

引入: 自定義

 

有一個小孩子,她能夠把吃下去的東西消化一部分,另一部分吐回來,完好如初。有一天,她想要知道心臟長什麼樣子,但是沒有人願意告訴她。她知道自己也有心臟,於是,她把自己吃下去,吐回來自己缺了右腿,她高興了,深信如此重複必有一次能夠看到自己可望了解的心臟──即使多少次是未知。她缺了左手,然後她缺了左腿,接著她缺了小腸,最後,終於吐出裸露的心臟,她笑了──失去下顎的上唇沒有顫抖,失去左鄰的右眼沒有淚,失去外衣的軟腦內沒有痛楚,失去肉體的靈魂沒有遺憾。

 

巢狀迴圈指的是多個以內外關係存在的迴圈交織作用,這經常用在多個變數求所有變化與結果。以下程式實現輸入三個數值,把1 到該數且三者串連的所有可能列出。

]Function test(ByVal test1 As Integer, ByVal test2 As Integer, ByVal test3 As Integer)

]For i1 As Integer = 1 To test1 Step 1

]For i2 As Integer = 1 To test2 Step 1

]For i3 As Integer = 1 To test3 Step 1

]MsgBox(i1 & ", " & i2 & ", " & i3)

]Next i3

]Next i2

]Next i1

]End Function

]

]test(1, 2, 2) //MsgBox 依序顯示"1, 1, 1"、"1, 1, 2"、"1, 2, 1"、"1, 2, 2"。

 

初學者經常使用上面這種定型巢狀迴圈,以上面為例,最多帶三個變數,想要第四個變數一起參與,沒門。

 

這是一個對巢狀迴圈的誤解。確實在上例,這些For 語法組織成就如同鳥巢一般(如果經過縮排美化),簡單易懂。但是這種定型巢狀迴圈不是萬能,真正的巢狀迴圈多半如同文章開頭那個故事裡的小女孩──那可不是閑閑沒事寫來嚇人的──把從自己身上吐出來的東西再分解一次。

 

這通常使用到一個大迴圈,用來監看應該使用幾層,在每一層之內,把自己的參數處理後送入自己體內。

]Function test(ByVal testInput As Array, Optional ByVal testKnow As Array = Nothing)

]If (UBound(testInput) - LBound(testInput) + 1 = 1) Then

]For i1 As Integer = 1 To testInput(LBound(testInput)) Step 1

]MsgBox(Reline(testKnow, ", ") & ", " & i1)

]Next

]Else

]For i1Number As Integer = 1 To testInput(LBound(testInput)) Step 1

]test(ResSteal(testInput, LBound(testInput)), ResPush(testKnow, i1Number))

]Next

]End If

]End Function

]

]test(New Integer() {1, 2, 2}) //MsgBox 依序顯示"1, 1, 1"、"1, 2, 2"、"1, 2, 1"、"1, 2, 2"。

]test(New Integer() {1, 2, 2, 2}) //MsgBox 依序顯示"1, 1, 1, 1"、"1, 1, 1, 2"、"1, 1, 2, 1"、"1, 1, 2, 2"、"1, 2, 1, 1"、"1, 2, 1, 2"、"1, 2, 2, 1"、"1, 2, 2, 2"。

 

如果巢狀迴圈總是被定型,就會處處被限制,小女孩只會失手失腳,在看到心臟前抑鬱而終。喜劇就因為定型巢狀迴圈的限制而降華為悲劇。

 

也許妳注意到了,一個不定型巢狀迴圈通常寫成一個函式,這樣才能不斷吞吐自己於自己,並且在讀入參數時判斷參數的數量,如果到了最後一到防線,那麼就執行主要程序。如果還沒,則切出某一個,並把其他的再吞回自己之中處理。在這樣的結構中,通常出現ResSteal 函式來刪除陣列中的元素。

 

如果想到無限巢狀迴圈(也就是不定型巢狀迴圈),那麼肯定想到文字排列。在數學中,給予一組成員,則能夠在成員不重複的條件下將該些成員排成多種順序。比如給予"ABC" 便能夠回傳"ABC"、"ACB"、"BAC"、"BCA"、"CAB"、"CBA"。

]Function Permutation(ByVal Elements As Array) As Array

]If (Elements Is Nothing) Then

]Return Nothing

]End If

]If (UBound(Elements) - LBound(Elements) + 1 < 2) Then

]Return Elements(LBound(Elements))

]End If

]Dim Result As Array = Nothing

]If (UBound(Elements) - LBound(Elements) + 1 = 2) Then

]Dim First As Array = Array.CreateInstance(ArrayType(Elements), 2)

]First(LBound(First)) = Elements(LBound(Elements))

]First(UBound(First)) = Elements(UBound(Elements))

]Dim Second As Array = Array.CreateInstance(ArrayType(Elements), 2)

]Second(LBound(Second)) = Elements(UBound(Elements))

]Second(UBound(Second)) = Elements(LBound(Elements))

]Result = Array.CreateInstance(Elements.GetType, 2)

]Result(LBound(Result)) = First

]Result(UBound(Result)) = Second

]Else

]For i1Elements As Integer = LBound(Elements) To UBound(Elements) Step 1

]Dim ThePermutation As Array = Permutation(ResSteal(Elements, i1Elements))

]For i1Permutation As Integer = LBound(ThePermutation) To UBound(ThePermutation) Step 1

]ThePermutation(i1Permutation) = ResPush(ThePermutation(i1Permutation), Elements(i1Elements), 0)

]Next

]Result = ResHang(Result, ThePermutation)

]Next

]End If

]Return Result

]End Function

]

]Dim test As Array = Permutation(New String() {"A", "B", "C"})

]For i1 As Integer = LBound(test) To UBound(test) Step 1

]MsgBox(Reline(test(i1), Nothing))

]Next

文章標籤
全站熱搜
創作者介紹
創作者 GPhettoH 的頭像
GPhettoH

歇息,等待明日的天空

GPhettoH 發表在 痞客邦 留言(0) 人氣(192)