假期即將結束,用最後這兩天溫習一下幾種經典排序演算法,總結一下,如有錯誤,請不吝指出:
1.基本概念:
1).穩定排序:當待排元素中有相同元素時,排序完後這些相同元素的相對位置與原來一致。
例如『1a
,2a,5,4,1b
,3,2b
』排序完後『1a
,1b,2a
,2b,3,4,5』
2).原地排序:指排序時只需要使用到固定大小的臨時空間,不需要使用與元素個數或元素型別相關大小的額外空間。
2.排序分類:
1).按排序方式分:
插入排序:直接插入排序,希爾排序;
交換排序:快速排序,氣泡排序;
選擇排序:直接選擇排序,堆排序;
歸併排序:歸併排序;
分配排序:桶排序,基數排序;
2).按一般平均時間複雜度分:
o(n2):直接插入排序,氣泡排序,直接選擇排序;
o(nlg(n)):快速排序,堆排序,歸併排序;
o(n1+a),0
o(n):桶排序,基數排序;
假設待排陣列為r[1...n],型別為簡單int型,取值為[1, 100],從小到大排序。
3.直接插入排序:
3.1基本思想:把陣列分為無序區和有序區,從無序區取出乙個元素,插入到有序區中。排序開始時,有序區為r[1],無序區為r[2...n],選擇r[2],插入到r[1]之前(之後),此時r[1,2]為有序區,r[3...n]為無序區。繼續這個步驟,直到r[1...n]都為有序區,排序完成。
3.2 關鍵點:查詢插入的位置,在查詢時,可以利用臨時變數儲存待排元素,然後依次向後移動比待排元素大的元素,為它留出位置。
3.2 演算法分析:原地排序,穩定排序,在待排陣列基本有序時比較次數少,效率較好,平均時間複雜度o(n2)。
4.氣泡排序:
4.1基本思想:每一趟「冒泡」過程,通過比較和交換把最大的元素移動到r[n]。排序開始時,比較r[1]和r[2],如果r[1] > r[2],交換r[1]和r[2],然後比較r[2]和r[3],如果r[2] < r[3],繼續比較r[3]和r[4],以此類推到r[n],完成第一趟冒泡,此時r[n]為最大元素。然後開始第二趟從r[1]到r[n-1]的冒泡,第三趟...直到第n-1趟,r[1]肯定是最小元素,排序完成。
4.2關鍵點:相鄰元素的比較與交換,以及最後冒泡的終點為n, n-1, n-2...到2,如果每次都冒泡到n,排序後元素為從大到小。
4.3演算法分析:原地排序,穩定排序,在待排陣列基本有序時交換少,效率交好,平均時間複雜度o(n2)
5.直接選擇排序:
5.1基本思想:同樣分為無序區和有序區,每一次選擇,都選擇當前無序區中最小的元素,並與無序區的第乙個元素交換,然後該元素所在位置變為有序區。排序開始時,r[1...n]為無序區,比較所有n個元素,找到最小值r[k],與r[1]交換,此時r[1]為有序區,r[2...n]為無序區。然後繼續在無序區中查詢最小元素,直到有序區為r[1...n],排序完成。
5.2關鍵點:跟蹤記錄當前找到的最小元素的值與位置,完成查詢後,與無序區的第乙個元素交換。
5.3演算法分析:原地排序,穩定排序,不管待排陣列是否基本有序,演算法每次都要比較無序區的所有元素,平均時間複雜度為o(n2)
6.快速排序:
6.1基本思想:分治法的思想,首先選擇乙個基準元素r[k](設其排序後的位置為m),然後遍歷所有待排元素,將比基準元素小的元素放在其左邊r[1...m],比它大的元素放在其右邊r[m+1...n],形成r[1...m]r[m]r[m+1...n]的布局,然後進一步分別對左,右兩邊呼叫快速排序演算法進一步排序。
6.2關鍵點:首先是基準元素的選擇,一般選擇第乙個元素或最後乙個元素,也可以使用概率演算法隨機選擇乙個元素;其次是陣列是否越界的判斷,注意在r[1,2]r[3]r[4...n]或r[1...n-3]r[n-2]r[n-1,n]等特殊邊界情況下的資料交換和判斷,防止越界。
7.堆排序:
7.1基本思想:
將待排陣列看成一棵完全二叉樹的遍歷,即r[1]是樹根,r[2]和r[3]是r[1]的孩子,r[4]和r[5]是r[2]的孩子,以此類推,r[1...n]可以構造為一棵完全二叉樹。
堆的概念:分為大根堆和小根堆,大根堆r[i] > r[2i]且r[i] > r[2i+1],小根堆r[i] < r[2i]且r[i] < r[2i+1],從樹的角度看就是大根堆的任意父節點的值,都比其兩個孩子節點大,小根堆反之。
演算法通過構造大根堆來獲得當前最大元素,每次的最大元素都處於r[1],即樹根位置。第一次構造後,當前最大元素處於r[1],然後交換r[1]與最後乙個元素r[n]。此時r[n]為有序區,r[1...n-1]為無序區。第二次構造堆從r[1...n-1]中構造,然後交換r[1]和r[n-1],以此類推。
7.2關鍵點:每次比較需要從k無序區最後乙個元素r[k]到r[2],分別與各自父節點比較,即r[(k - 1)/2],並保證r[(k - 1) / 2] > r[k],從而完成每次的堆構造。
7.3演算法分析:原地排序,非穩定排序,堆排序是選擇排序的優化,選擇排序每次都要比較所有剩餘的元素,做了很多重複工作,堆排序在每次構造堆時,都會調整堆,使得後面的構造更加快速,時間複雜度為o(nlg(n))。
8.歸併排序:
8.1演算法思想
(2路歸併):有r[1...m]和r[m+1...n]兩個已經排序好的序列,有臨時序列t[1...n],從r[1...m]和r[m+1...n]的開頭r[1]和r[m+1]開始,選擇較小的元素放入t[1],如果r[1]較小,則接下來比較r[2]和r[m+1],選擇較小的放入t[2],以此類推,比較完r[1...m]或r[m+1...n],最後把另乙個未使用完的序列接著放到t[1...n]中。
與快速排序類似,但是歸併是自底向上,從相鄰的2個元素的排序歸併,到相鄰的2路共4個元素的歸併,最後到2路共n個元素的歸併。
8.2關鍵點:歸併時,某一路剩餘未歸併的元素要接到臨時序列的後面。
8.3演算法分析:非原地排序,穩定排序,在最後一次歸併時空間複雜度為o(n),時間複雜度為o(nlg(n))
9.希爾排序:
9.1演算法思想:按步長分階段排序。步長為d,將所有距離為d的元素劃分為一組,在組內進行插入排序。不斷減少d值(可以d/=2),最後在d=1階段完成後,排序完成。
9.2關鍵點:步長d最後必須為1,保證所有元素都在同一組,完成排序。注意元素個數無法整除d時,分組邊界的判斷。
9.3演算法分析:原地排序,非穩定排序,是插入排序的優化,每階段只需完成d次的插入排序,每次資料量為n/d,時間複雜度為 o(n1+a),0
10.桶排序:
10.1演算法思想:演算法適用於已知元素關鍵值取值範圍的陣列。設建立100個「桶」,遍歷所有元素r[1...n],當r[k] == v時,把r[k]放入第v個桶,在所有的元素分配完後,從第乙個桶到最後乙個桶串起來,就是排序好的陣列。
10.2關鍵點:元素關鍵值取值範圍必須知道,否則可能需要無限個「桶」。「桶」可用鍊錶實現,元素r[k]放入「桶」v可實現為r[k]接到鍊錶v的後面。
10.3演算法分析:穩定排序,使用鍊錶時,不需要額外空間,但仍需要申請煉表頭作為「桶」,為非原地排序。只需要遍歷分配r[1...n],然後收集,時間複雜度都為o(n),因此演算法時間複雜度為o(n)
11.基數排序:
11.1演算法思想:桶排序的公升級,對於有多個關鍵值型別的元素陣列,分別對每種關鍵值型別進行桶排序。關鍵字可以是數值,可以是字串。例如數字排序可以對其個位,十位,百位...都分別進行桶排序,桶個數為數值取值0~9共10個;如果是字串,可以對其每一位的字元,進行桶排序,桶個數為字元的取值a~z共26個。
11.2關鍵點:關鍵值的劃分,關係到桶的個數,也關係到所需桶排序的次數。
11.3演算法分析:穩定排序,非原地排序,每個關鍵字的桶排序在n的時間內完成,共有m個關鍵字,演算法時間複雜度為o(m * n)。
幾種經典排序演算法
據說第乙個正確的快排演算法程式是在快排思想提出後的兩三年才有人寫出來,我們都是站在巨人的肩上碼 啊。演算法 一趟排序為,選出乙個哨兵元素,可以為左邊第乙個,然後從序列的最左邊開始遍歷,選出比哨兵元素小的元素下標,標記為r,從序列的左邊開始遍歷,選出比哨兵元素大的元素下邊,標記為l,然後r l下邊的元...
經典排序演算法總結
排序演算法是離散數學和資料結構學科最基本的演算法,雖然知道這些排序演算法的名字,但是一直沒有研究過它們的實現原理。現在把它們收集起來,並一一親自實現,來加深對排序演算法的理解。1,氣泡排序 最簡單的排序演算法,從第乙個元素開始比較相鄰元素大小,如果前邊元素大於後邊元素則交換位置,否則將下標移到下乙個...
經典排序演算法總結
插入排序 選擇排序 歸併排序 排序方法 平均情況 最好最差 空間複雜度 穩定性氣泡排序o n2 o n 2 o n o n o n2 o n 2 o 1 o 1 穩定快速排序o nlogn o nlog n o nlogn o nlog n o n2 o n 2 o nlogn o nlog n 不...