繼續讀啊哈磊算法有感系列,繼續昇華。上一篇是冒泡排序,在結尾總結了一下冒泡排序的缺點——時間複雜度O(N*N)太大。這一篇來講一下快速排序,快速排序能夠在多數狀況下克服冒泡排序的缺點(最壞的狀況下和冒泡排序的時間複雜度同樣)。下面咱們先來講說快速排序的思想與過程,與上一篇從過程到思想的思考方式不一樣,這一次咱們的思考過程是從思想到過程——算法
快速排序的思想:數組
利用二分的思想,先在待排序子數組中選定一個基準數(做爲中間值)、一個左初始位(待排序子數組的左端點位。若對整個數組進行排序,則左端點位爲數組的0索引位),一個右初始位(待排序子數組的右端點位。若對整個數組進行排序,則右端點位爲數組的length-1處索引位),而後找到一個位置,該位置左側的數均小於基準數,右側的數均大於基準數。在此基礎上,對待排序子數組進行二分,分別爲待排序子數組中基準數以左,左初始位以右的孫子數組1;和待排序子數組中基準數以右,右初始位以左的孫子數組2。以後進行遞歸,將孫子數組1和2分別做爲待排序子數組進行同上排序。函數
快速排序的過程(與上一篇中思想就是對過程的抽象與總結相反,過程就是對思想的具體與落實):測試
一、選定待排序子數組及其基準數、左初始位、右初始位(若左初始位小於右初始位則繼續,不然中止);this
二、找到基準數的交換位置,在左初始位和右初始位分別安排一名哨兵,先是右哨兵向左走,直到找到第一個比基準數小的數爲止;而後是左哨兵向右走,直到找到第一個比基準數大的數爲止。交換左右哨兵位置處的數值,而後哨兵繼續前行(先右後左),繼續交換,直到左右哨兵相遇前,中止。至此第一輪排序結束了,左哨兵以左都小於等於基準數,右哨兵以右都大於等於基準數;spa
三、交換左哨兵和基準數的數值,至此基準數以左均小於等於基準數,基準數以右都大於等於基準數;3d
四、以基準數所在的位置對待排序子數組進行二分,分爲孫子數組1和2;code
五、對孫子數組1和2進行遞歸,回到第一步,孫子數組1的左初始位爲待排序子數組的左初始位並依然以左初始位的數爲新的基準數、右初始位爲基準數位-1,孫子數組2的左初始位爲基準數位+1並以左初始位的數位新的基準數、右初始位爲待排序子數組的右初始位。blog
等到孫子數組2的左初始位和孫子數組1的右初始位相遇時,這場排序就結束了。整個待排序子數組將會按照從小到大進行排序。排序
接下來咱們將具體的過程轉換爲代碼:
#Exchange the two value. function ExchangeValue($i,$j, $studentScore, $studentName) { #Exchange the score. $s = $studentScore[$i] $studentScore[$i] = $studentScore[$j] $studentScore[$j] = $s #Exchange the name. $n = $studentName[$i] $studentName[$i] = $studentName[$j] $studentName[$j] = $n } function SortScores($left, $right, $studentScore, $studentName) { if($left -le $right) { #Sort begin. #The $left is base number, the $left and $right also represents the location of the sentries' start points. $i = $left $j = $right #The right sentry must go first every time while the sentries not meet each other. while($i -ne $j) { while(($studentScore[$j] -ge $studentScore[$left]) -and ($j -gt $i)) { $j-- } #And then the left one. while(($studentScore[$i] -le $studentScore[$left]) -and ($i -lt $j)) { $i++ } #If the left entry doesn't meet the right entry, exchange the left and right number. If($i -lt $j) { ExchangeValue $i $j $studentScore $studentName } } #Exchange the value from the locations of the left entry and the base number. ExchangeValue $left $i $studentScore $studentName #Now "$i" is the new location of the base number. #Sort the new left part. $newRight = $i-1 $newLeft = $i+1 SortScores $left $newRight $studentScore $studentName SortScores $newLeft $right $studentScore $studentName } } function PrintSortedScores($count, $studentScore, $studentName){ #Print the sorted result. Write-Host "Below is the sorted result:" for($i=0;$i -le $count-1;$i++) { $j=$i+1 $tip = "NO."+$j+":"+$studentName[$i]+",score:"+$studentScore[$i] Write-Host $tip -ForegroundColor Green } } #This is the entry of this program. #Collect the students' scores. $count = Read-Host "Enter the amout number of the students" #Convert to int type. $count = [int]$count $studentName = New-Object System.Collections.ArrayList $studentScore = New-Object System.Collections.ArrayList for($i=1;$i -le $count;$i++) { $name = Read-Host "Enter the name" $score= Read-Host "Enter the score" #Convert to int type. $score = [float]$score $studentName.Add($name) $studentScore.Add($score) } $leftNum = 0 $rightNum = $count - 1 SortScores $leftNum $rightNum $studentScore $studentName PrintSortedScores $count $studentScore $studentName
函數SortScores是快速排序算法的核心,其中關鍵的判斷我用橙色高亮了出來。
在PowerShell中運行這段代碼,並輸入一些測試數據,結果以下:
冒泡排序的交換距離是相鄰的兩個元素,而快速排序中左右哨兵並非相鄰的,因此交換的兩個元素也不是相鄰的,最壞的狀況,左右哨兵碰頭的時候交換纔會交換相鄰的兩個元素。若是每次都是最壞的狀況(每次都是左右哨兵相鄰才交換),那快速排序的時間複雜度和冒泡排序是同樣的。但只要不是最壞的狀況,快速排序的時間複雜度都要小於冒泡排序,它的平均時間複雜度是O(NlogN)。