VB程序設計
VB6.0似乎已經成為開發(fā)者的往事频蛔,但是Microsoft Office系列軟件的控制和操作仍然是基于VB6.0的。本項目是為所有學習VB6.0的同學而建立的照雁。
問題1: 排序算法
排序算法是計算機程序設計中最經典的算法蚕愤,在計算機的專業(yè)課《數據結構》中有大量的討論和分析答恶。我們在這里只討論最簡單的選擇排序和冒泡排序。討論從一個填空題開始萍诱。
' 功能:將數組a()中的元素按從小到大排序'
' 參數:數組a()的下標索引為從1到30'
Sub bubble_sort(a() As Integer)
For i = 1 To 29
For j = 【2】
If a(i) > a(j) Then
m = a(i): a(i) = a(j): a(j) = m
End If
Next j
Next i
End Sub
問題:【2】這個地方應該填什么悬嗓?是 i+1 To 30?還是 1 To 30-i裕坊?
- 首先包竹,最正確的姿勢是記住籍凝!甭管是冒泡還是選擇排序周瞎,這里j的取值應該與i正好錯開1,【2】處應該填:i+1 To 30
- 其次饵蒂,理解排序的原理声诸。為什么不是:1 To 30-i呢?
首先退盯,我們要明確目標彼乌。因為要對數組a()從小到大排序,我們期望:依次掃描a()中的每個元素渊迁,每掃描到一個元素a(i)慰照,都使得它是剩下的元素(從a(i)到a(30))中最小的。怎么做到呢宫纬?可以從a(i)一直掃描到a(30)焚挠,找到最小的元素a(p),令a(i)和a(p)的值交換(注意:這里不能直接讓a(i)=a(p)漓骚,否則蝌衔,a(i)的原有值就不見了)。用下面的偽代碼表示:
'代碼塊1
Sub selection_sort(a() As Integer)
For i = 1 To 30
'從a(i) 到 a(30)中找到最小的元素a(p)'
'將a(i)和a(p)的值交換'
Next i
End Sub
那么蝌蹂,怎么從a(i) 到 a(30)中找到最小的元素a(p)呢噩斟?可以這樣做:
'代碼塊2
p = a(i) '首先,假設a(i)就是最小的'
For j = i To 30 '從a(i) 掃描到 a(30)'
If p > a(j) Then '一旦發(fā)現p比a(j)還大孤个,就讓p指向a(j)'
p = a(j)
End If
Next j
上述做法剃允,就是選擇排序的思想。我們可以將代碼優(yōu)化下:
首先齐鲤,j 不必從 i 開始掃描斥废,因為當 j = i 時,a(j)沒有必要跟a(p)進行比較(這時给郊,p 也等于 i)牡肉。
其次,p 指向a(i)的索引就可以了淆九,沒有必要指向a(i)统锤。
'代碼塊3
p = i ' 假設a(i)就是最小的
For j = i+1 To 30
If a(p) > a(j) Then '一旦發(fā)現a(p)比a(j)還大毛俏,就讓 p 指向 j
p = j
End If
Next j
這時,將代碼塊3嵌入代碼塊1饲窿,就可以得到完整的選擇排序的代碼了:
'代碼塊4
Sub selection_sort(a() As Integer)
For i = 1 To 30
'從a(i) 到 a(30)中找到最小的元素a(p)
p = i '假設a(i)就是最小的
For j = i+1 To 30
If a(p) > a(j) Then '一旦發(fā)現a(p)比a(j)還大煌寇,就讓 p 指向 j
p = j
End If
Next j
'將a(i)和a(p)的值交換(代碼略)'
Next i
End Sub
- 經過上面的推演,我們就得到了一個雙重循環(huán)逾雄。反過來阀溶,如果直接拿到的就是這樣一個雙重循環(huán)的話,會不會感覺閱讀起來很困難嘲驾?實際上淌哟,只要把外層循環(huán) i 固定為某個特定的值來理解內層循環(huán) j 就可以了。
- 再來看冒泡排序法辽故。它與選擇排序法最大的不同在于:在其內層循環(huán) j 中,一旦發(fā)現a(p)比a(j)還大腐碱,就讓 a(p) 和 a(j) 的值交換誊垢,而 p 是始終指向 i 的(因為a(p)中一直存放最小的值,所以症见,p就沒有必要再移動了)喂走。這樣,每經過一次內層循環(huán)谋作,就相當于剩下元素中具有最小值的那個元素(具有最小的質量)從水底下浮出來了芋肠,因此稱為“冒泡排序法”。具體代碼如下:
' 代碼塊5
Sub selection_sort(a() As Integer)
For i = 1 To 30
' 從a(i) 到 a(30)中找到最小的元素a(p)
' 假設a(i)就是最小的遵蚜,并且始終存放剩余元素中的最小值
For j = i+1 To 30
If a(i) > a(j) Then '一旦發(fā)現a(i)比a(j)還大帖池,就讓它們交換
m = a(i): a(i) = a(j) : a(j) = m
End If
Next j
Next i
End Sub
- 那么,上面的“選擇排序”和“冒泡排序”哪個更優(yōu)呢吭净?也就是睡汹,哪個排序算法的速度更快呢?顯然是選擇排序寂殉。因為冒泡排序在最壞的情況下需要 30-(i+1)+1=30-i 次 a(j) 和 a(i) 的交換囚巴,而選擇排序只要交換交換 1 次即可。
- 再來看同學的問題友扰,同學嘗試將內層循環(huán) j 設置為 1 To 30-i 有什么問題呢彤叉?事實上,這樣做就意味著:該做的沒有做村怪,不該做的卻費力去做秽浇。第一,該做的沒有做实愚。你看兼呵,這樣做只能找到從a(1)到a(30-i)中的最小值兔辅,那a(30-i)之后的元素呢?第二击喂,不該做的卻費力去做维苔。為了讓 a(i) 為剩下元素中的最小值,還需要做許多冗余的工作:它還要跟它之前的已經比它還小的元素依次比較懂昂,這完全是沒有必要的介时,因為比它大的元素,只可能在它后邊凌彬。
- 練習沸柔。如果我們非要將內層循環(huán) j 設置為 1 To 30-i 呢?如果非要這樣做铲敛,外層循環(huán) i 的設置必須改變褐澎,它必須從 a(i) 的最后一個元素倒著走向 a(i) 的第一個元素,以保證:每次a(i)中都存放最大值伐蒋。這樣的程序該如何寫工三?請同學們自行練習。