java 部分正确性_深入理解java快速排序的正确性
說起快速排序,很多人都能夠寫出一個正確的快速排序,但就快速排序的正確性,就無從探究了。為什么說寫出來的快速排序就是正確的。在快速排序中間的關鍵幾步,以什么樣的數據組織來保障快速排序的正確性。本文以《數據結構與算法 Java語言描述》中所描述的快速排序來進行理解,以查看其中的正確性。
首先查看排序的整體偽代碼:
其中,中間所涉及的med算法如下所示:
以上即整個快速排序算法以及相對應的獲取pivot的算法。
那么我們首先從源碼上分析整個排序算法的正確性,以及在特殊的控制點上是如何取得正確的(在后續的說明中 小于的意思為小于或等于 大于的意思為大于或等于,即不對=pivot的數進行特殊處理)。
第1步
判斷適用于快速算法的必要性,我們知道在一定范圍之內,快速排序是不如插入排序的。這個范圍依賴于具體的算法步驟分析。在本文中,這個范圍被設定為CUTOFF,即如果這個排序的范圍在CUTOFF之內,則就不再使用快速排序進行排序,而是直接使用插入排序對數據進行排序。排序完畢之后,即整個數組排序完畢。而且還有一個作用,即后續的排序方法中,整個數組的排序范圍一定在大于CUTOFF處,這就保證了能夠取得足夠的數進行計算。
第2步
取得正確的pivot,即選出一個數據,來作為數組分組的中間數。在整個排序過程中,比這個數小(或等于)的數將排在數組的左邊,而比之大(或等于)的數將排在右邊。這個選擇的過程由方法med(int[],int,int)來完成。它選擇整個數組中最左邊,最右邊,以及中間的數進行比較,將處于中間數年作為pivot。
然后,在上面的med算法中,這個過程還將作更多的工作,這個工作即是對這三個數進行排序,保證最小的數放在a[left]位置上,最大的數放到a[right]上,而中間的數放在a[center]上。并且返回a[center]這個數。
值得注意的是,算法將a[center]和a[right-1]即倒數第二個數進行交換。
通過解讀后面的算法得知,在進行a[left],a[center],a[right]之間的數據交換之后,在后續的判斷當中,將不再對a[left],a[right]進行數據判斷和交換工作,因為在這里已經作了一次處理了。而將a[center]與a[right-1]作為交換,是因為要將a[center]放到數組的最后,避免在數據處理過程中被交換了。
第3步,第4步
整個排序的核心部分,即比較并交換部分。首先,將左起點設為left,右起點設為right-1。但這兩個點的數并不參與比較,因為在前面的med算法中已經進行處理過了。我們知道left比pivot,right-1即為pivot,而right比pivot大。所以在整個循環過程中,首先即對起點進行了+1操作,以將比較操作往前+1,以跨過最開始的起點。我們來看這兩個比較和交換的代碼:
第一個正確性:i和j永遠不會越界,這是因為a[right]是比pivot大的,所以i一定會停止,而a[left]是比pivot小的,所以j也一定會停止。當兩種情況的任意一種產生時,在后續的比較中,都會停止while,而導致i和j最終停止處理。
第二個正確性:當這兩次比較過程中,i和j的位置有3種情況。ij。
對于第一種情況,即i和j沒有相遇,這是最常見的一種情況。在沒有相遇的情況下,a[i]所處的點,大于pivot,而a[j]所處的點小于pivot,這時將在后續處理中,交換這兩個點,并且將在下一次循環中再一次移動i和j。
對于第二種情況下,即a[i]=a[i]=pivot,這時,并不需要交換i和j,因為它們本身即在同一個點上。
對于第三種情況,即在相遇時碰到的最常見的情況,即a[i]在一個比pivot大的一個點上,而當j=i的情況,判斷出a[j]大于pivot,而自然進行下一步的–操作,這時即產生了i>j的情況,通常情況下都是i=j+1,即j在i有前一格。
對于上面的三種情況,第二種情況和第三種情況,均會使得while循環中止,對于第一種情況,將繼續進行循環,最終達到第二種或第三種情況以達到中止的狀態。
第三個正確性:即在未發生第4步的交換之前,i之前(不包括i)的數據均小于pivot,而j之后的數據均大于pivot。
第四個正確性:在發生了交換之后,仍然保持第三個正確性。這是因為,交換過程中,并沒有發生i和j的改變,第三個正確性仍然成立。
第5步
我們現在來分析一下,while中止時i所處的點對于pivot以及i之前的數據的情況。這個情況有利于分析第5步操作的必要性和正確性。
第一種情況:在通常的情況下,即第3步,第4步的操作過程中,i和j在數組的中間相遇。由上面的第3步,第4步分析過程中的第二正確性可以看出整個最外層的while(循環均會在當i=j或ipivot時循環才會退出)。而第三,四正確性保證了以i作為分界線兩邊數據被分成了2組,即a[i]大于pivot。
第二種情況:i從最開始的內層循環開始就沒移動過,即i在left+1處,[left+1,rithg-2]均大于pivot,這種情況下。仍然滿足以上的
特殊,因為a[left]小于pivot,而a[i]=a[left+1]大于pivot。
第三種情況:j從最開始的內層循環就沒移動過,即j在right-2處,而此時i則在right-1處,即[left+1,right-2]均大于pivot。這種情況下,仍然滿足以上的情況,因為a[left]小于pivot,而[left+1,right-2]均小于pivot,a[i]=a[right-1]大于(這里大于等于被認為大于)pivot。
由于上面三種情況下,均滿足a[i]大于pivot,且i之前的數據均小于pivot,所以i自然地被認為是整個數組劃分點的中點。且下一步的操作要將比較數移到正確的位置上來(它原來在right-1處)。 由于i點即為分界點,且a[i]大于pivot,所以這里,將兩個點的數據交換,即a[i]為pivot,而原來的a[i]被移到a[right-1]處,仍然滿足i之前的數據小于pivot即a[i],而i之后的數據大于pivot即a[i]。在之前的判斷中,均以pivot為比較,現在終于可以將pivot放到正確的地方了,即a[i]處。
第6步
在第5步之后,i作為分界點,分相應的數據已經劃到正確的位置上,滿足i之前的數據比a[i]小,i之后的數據比a[i]大,所以分別對前部分進行排序,對后部分進行排序。
整個排序部分結束。
在整個排序過程中,正是由正確而緊湊地代碼保證了排序的正確性,包括pivot的尋找,以及下限和下限的保證,確保在過程中不會出現越界以及交換錯誤的情況出現。
相關文章:
作者: flym
I am flym,the master of the site:)查看flym的所有文章
總結
以上是生活随笔為你收集整理的java 部分正确性_深入理解java快速排序的正确性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于java的学生点名系统_基于java
- 下一篇: java用jsoup爬网页数据_java