排序問題的解決方案是演算法問題當中最多的,常見的有插入排序,選擇排序,氣泡排序,歸併排序,快速排序,堆排序等,下面將對不同的排序演算法進行分析。假設均為實現從小到大排序,計算空間複雜度時,不考慮原本儲存元素的空間,只考慮實現演算法需要的額外空間。
插入排序的基本思想是:從待排序的元素中選出乙個,插入已排好序的元素佇列中。重複操作直到所有元素全部被處理完。插入過程可以有兩種情況:(1).若已排好序的元素存放在陣列當中,要插入乙個新的元素,要將已排好的元素佇列中比該新元素大的整體向後移動一位,留出乙個空間存放該元素。這種情況下,需要額外的空間存放排好序的佇列,因此空間複雜度為o(n)。插入元素,首先需要確定插入點,然後移動插入點後元素,因此時間複雜度為o(n2)。(2).若已排好序的元素存放在鍊錶當中,對於每個元素都需要開闢額外空間儲存,因此空間複雜度為o(n)。插入元素,只要確定插入點即可,針對鍊錶的插入是常數級操作,因此時間複雜度為o(n)。整體來說,該演算法是最容易理解,也是最容易實現的。
選擇排序在插入排序演算法上進行了改進。從待排元素中選擇最小的乙個,和這個待排元素佇列最前面的乙個進行交換,這樣該元素就比它後面的所有元素都小,待排元素就變成了該元素後面的所有元素。重複操作直到待排元素只剩下乙個。該演算法中,外層迴圈每次減小待排元素數量,內層迴圈尋找待排元素中最小的乙個。直到遍歷所有待排元素之後才能確定哪個最小,確定後才能交換。因此,該演算法的時間複雜度為o(n2),由於不需要額外空間存放待排元素或已排好序的元素,因此其空間複雜度為常數級o(1)。
氣泡排序對選擇排序進行改進。將待排元素佇列看作是豎形排列,從下到上進行處理:兩兩相鄰元素進行比較,如果下面的比上面的小則兩者交換,直到到達頂端。這樣頂端的元素就比其下面的所有元素都小,待排元素就變成了該頂端元素下面的所有元素。多次迴圈處理直到待排元素數隻剩下乙個。該演算法中,外層迴圈每次減小待排元素數量,內層迴圈從底向上兩兩元素比較交換,根據比較結果交換。因此,該演算法的時間複雜度為o(n2),同樣不需要額外空間存放待排元素或已排好序的元素,因此其空間複雜度為常數級o(1)。
歸併排序基本思想是:將待排元素前後分成兩部分,分別進行排序,使這兩部分內部是有序的,然後對這兩部分進行合併。因此歸併排序用到了遞迴呼叫,對待排元素佇列對半分並對這兩部分分別呼叫歸併排序,因此遞迴的結束條件是待排元素只剩下乙個。合併過程需要做的是,將兩段元素佇列分別拷貝進入臨時儲存空間,後按元素順序合併存入原來的空間當中。根據演算法,遞迴呼叫的層數為log2n,而每層都對所有的元素進行了歸併的操作,操作量為o(n),因此時間複雜度為o(nlog2n)。同時由於歸併過程開闢了新的空間對元素佇列進行臨時儲存,所以空間複雜度為o(n)。
快速排序的基本思想是:以待排元素佇列的第乙個作為標桿元素,將所有待排元素分為前後兩部分,前面部分的元素都比標桿元素小,後面部分的元素都比標桿元素大,標桿元素則放置於這兩部分之間。然後對前後兩部分元素分別再進行快速排序,即遞迴呼叫,呼叫結束條件是待排元素只剩下乙個。理想情況下,每次待排元素被分成的前後兩部分大小是一致的,因此遞迴呼叫層數為log2n。每層都完成了對元素佇列的對半分操作,操作量為o(n),因此理想情況下時間複雜度是o(nlog2n)。極端情況下,元素本身是有序的,對半分的結果就是一半沒有任何元素,這種情況下,遞迴呼叫層數為n,整體時間複雜度是o(n2)。由於對半分的過程中沒有開闢額外空間,因此其空間複雜度為常數級o(1)。
堆排序採用了完全二叉樹的思想,將待排序元素佇列從邏輯上看做乙個完全二叉樹,佇列從1開始編號,後依次從上到下,從左到右對應完全二叉樹的每乙個節點。這樣得到的二叉樹子節點的編號等於父節點編號的兩倍或兩倍加1。在此基礎上構建大根堆,即對於所有節點,它要比它的兩個子節點小,要比它的父節點大。建堆完成後可將堆頂元素,也就是根,與堆中最後乙個節點交換元素值。堆大小減1,再次調整堆為大根堆後再做元素交換,堆大小再次減1。如此直到堆大小變為1後即完成了堆排序。構建堆的完全二叉樹層數為log2n,排序過程中的調整最大深度也為log2n,需要對所有元素進行調整,所以時間複雜度為o(nlog2n),因此時間對整個過程中沒有開闢額外空間,因此其空間複雜度為常數級o(1)。
對以上六種排序演算法進行過程描述後可以看出,思路簡單的演算法時間和空間複雜度相對高,實現相對困難的演算法在時間和空間複雜度都要好。在實際應用過程中,要根據實際情況選擇相應的演算法。如原始資料已經基本有序,就不適合選擇快速排序演算法,否則易出現時間複雜度為o(n2)的極端情況。
在測試中,將氣泡排序,歸併排序,快速排序,堆排序以c語言**方式實現,所測試資料通過c語言隨機函式產生,規模為20000個,存放在檔案中。排序程式從檔案讀入資料排序後再次寫入到檔案。通過用cena程式評判軟體執行上面四個演算法程式的記憶體使用情況,執行所用時間情況如下:
氣泡排序:
歸併排序:
快速排序:
堆排序:
可知,在時間複雜度方面,氣泡排序最差,快速排序和堆排序基本相同,而歸併排序因為加入了記憶體申請和釋放的過程,因此實驗結果與理論分析存在一定的誤差。空間複雜度上,歸併排序所佔記憶體明顯大於其他三者,是因為歸併排序在運算時大量借助臨時記憶體完成排序。(該測評軟體顯示的記憶體使用情況包括程式執行的所有開銷)
由於實驗條件所限,只進行了20000個資料規模下的排序開銷測試。在實際應用中,特別是大資料時代,資料規模以gb計算,不同演算法在時空複雜度上的體現將會更加明顯。
各演算法源**請參考我相應的部落格。
各種排序演算法比較
花了很長時間終於把排序的基礎學了一下,這段時間學了很多東西,總結一下 學的排序演算法有 插入排序,合併排序,氣泡排序,選擇排序,希爾排序,堆排序,快速排序,計數排序,基數排序,桶排序 沒有實現 比較一下學習後的心得。我不是很清楚他們的時間複雜度,也真的不知道他們到底誰快誰慢,因為書上的推導我確實只是...
各種排序演算法比較
排序相關的演算法複雜度分析 下邊分別實現下各個演算法 簡單選擇排序 1 簡單選擇排序 2void select sort int a,intn 3 16 17swap a i a index 18 19 這裡簡單選擇排序之所以不穩定是因為交換的時候會打亂順序,例如 5,4,5,1,6。第一次交換後會...
各種排序演算法的比較
穩定的排序演算法有 直接插入,冒泡,歸併,基數排序。一.快速排序 快排的三個步驟 1.選取樞紐元,一般用三數中值法,即求得left,center,right的中位數 不要用第乙個數,如果原始資料是倒序,效率將會很低 2.根據樞紐元把輸入資料劃分成為兩部分,左半部分的數比樞紐元小,右半部分比樞紐元大。...