在之前的兩篇blog中,已經簡要的說明了冒泡排序和快排的原理、過程圖示以及代碼實現。這里主要討論的是兩種排序的復雜度以及一些常見的優化手段。
冒泡排序
【時間復雜度】
在整個序列完全是有序的狀態下,只需要執行第一次的內層循環。只要做好標記,我們就不用再進行后續的內層循環。此時時間復雜度為O(n);
再來計算最壞的情況。外層的循環每次都進行,那么會進行N次,而這N輪的比較次數分別是(n-1),(n-2),(n-3),(n-4)...1,0,所以總的比較次數為(0+1+2+...+n-1)=n*(n-1)/2,所以根據O法則,它的時間復雜度為O(n^2)。
【空間復雜度】
整個冒泡排序過程中,只用了一個可以重復利用的臨時變量,用於交換需要調換位置的元素,所以空間復雜度為O(1)。
【穩定性】
所謂的穩定性,就是能保證排序前2個相等的數其在序列的前后位置順序和排序后它們兩個的前后位置順序相同。冒牌排序是可以保證兩個相等元素前后的排列順序不發生變化。所以冒泡排序是穩定的。
【時間復雜度的平均情況】
其實最好最壞的情況都不難分析,但是平均情況的排序需要考慮的就是,n個元素的序列所有可能的情況下(即n!),時間復雜度的一個加權平均期望時間復雜度,需要結合概率論的知識,嚴格定量的推導是很復雜的。
這里可以稍微想想,這n!中排序的情況,順序和逆序的情況應該是對稱的。比如說,1和2,有[1,2]這個順序,就會有[2,1]這個順序;1,2,3三個元素,有[1,2,3]這個順序,就會有[3,2,1]這個順序。而冒泡排序中,我們可以想到的是,如果完全順序,就是n-1次,而完全逆序,就是n(n-1)/2次,其它的情況,可以想到隨着這種順序的程度,從完全順序到完全逆序不斷地轉換,那么這個次數應該是一個線性地變化過程。所以可以認為,這個平均值接近最差情況的一半,所以平均時間復雜度可以認為是O(n^2) 。
快速排序
【時間復雜度】
在整個序列完全有序,以及完全相等的情況下,每一次R的位置,從集合的最右側,經過n-1次滑動到L的位置,最終確定pivot(加入pivot每次取最左側的元素)不再參與下一輪的快排。那么,整個排序完成,會發生的快排操作次數為(n-1)+(n-2)+...+1=n(n-1)/2,與冒泡排序的最差情況一致。時間復雜度為O(n^2)。
這里用公式進行歸納,也可以得到最差的情況,公式比較難打,這里手寫拍照用圖片記錄了:
用同樣的方法,我們來推導最優的情況。盡管網上有直接給出情況是O(nlog(2)n),但是很少有將過程說清楚的。這里給出推導過程:
平均復雜度的情況更加復雜,這里就不進行推導了。最終的結果,平均復雜度也是O(nlog(2)n)。
【空間復雜度】
快排過程中,不需要臨時空間進行存儲元素,在原數組上就能完成,但是由於快排是遞歸調用,所以會消耗函數調用棧空間。在分區選擇最優的情況下,棧深度為log(2)n,所以空間復雜度最優為O(log(2)n),最差情況深度會變為n,所以復雜度為O(n)。平均情況下,遞歸深度也是對數級別的。
【穩定性】
由於pivot選擇不同會導致原數組中相同元素的位置不同(考慮用不同位置的同值元素作為pivot),所以快排並不穩定。