The Algorithms of sort - Python

https://github.com/TheAlgorithms/Python;本文內容出自於此。php

Sort Algorithms(排序算法)

Bubble(冒泡)

維基百科:冒泡排序英語:Bubble Sort,臺灣另一種譯名爲:泡沫排序)是一種簡單的排序算法。它重複地走訪過要排序的序列,一次比較兩個元素,若是他們的順序錯誤就把他們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。這個算法的名字由來是由於越小的元素會經由交換慢慢「浮」到數列的頂端。git

算法描述

  1. 比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。
  3. 針對全部的元素重複以上的步驟,除了最後一個。
  4. 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。

因爲它的簡潔,冒泡排序一般被用來對於程序設計入門的學生介紹算法的概念。github

特性:算法

最差時間複雜度:O(n^2)數組

最好時間複雜度:O(n)架構

平均時間複雜度:O(n^2)less

Python代碼實現:ide

View Code

輸出結果:final: [2, 4, 8, 13, 14, 26, 27, 28, 33, 35]svg


 


Insertion(插入)

維基百科:插入排序英語:Insertion Sort)是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,一般採用in-place排序(即只需用到O(1)的額外空間的排序),於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。oop

算法描述

通常來講,插入排序都採用in-place在數組上實現。具體算法描述以下:

  1. 從第一個元素開始,該元素能夠認爲已經被排序
  2. 取出下一個元素,在已經排序的元素序列中從後向前掃描
  3. 若是該元素(已排序)大於新元素,將該元素移到下一位置
  4. 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
  5. 將新元素插入到該位置後
  6. 重複步驟2~5

若是比較操做的代價比交換操做大的話,能夠採用二分查找法來減小比較操做的數目。該算法能夠認爲是插入排序的一個變種,稱爲二分查找插入排序

算法複雜度

若是目標是把n個元素的序列升序排列,那麼採用插入排序存在最好狀況和最壞狀況。最好狀況就是,序列已是升序排列了,在這種狀況下,須要進行的比較操做需(n-1)次便可。最壞狀況就是,序列是降序排列,那麼此時須要進行的比較共有{\displaystyle {\frac {1}{2}}n(n-1)}次。插入排序的賦值操做是比較操做的次數減去(n-1)次,(由於n-1次循環中,每一次循環的比較都比賦值多一個,多在最後那一次比較並不帶來賦值)。平均來講插入排序算法複雜度爲O(n^2)。於是,插入排序不適合對於數據量比較大的排序應用。可是,若是須要排序的數據量很小,例如,量級小於千;或者若已知輸入元素大體上按照順序排列,那麼插入排序仍是一個不錯的選擇。 插入排序在工業級庫中也有着普遍的應用,在STL的sort算法和stdlib的qsort算法中,都將插入排序做爲快速排序的補充,用於少許元素的排序(一般爲8個或如下)。

特性:

最差時間複雜度:O(n^2)

最好時間複雜度:O(n)

Python代碼的兩種實現:

View Code
View Code

輸出結果:final: [2, 4, 8, 13, 14, 26, 27, 28, 33, 35]


 


Merge(歸併排序)

維基百科:歸併排序英語:Merge sort,或mergesort),是建立在歸併操做上的一種有效的排序算法,效率爲O(n log n)。1945年由約翰·馮·諾伊曼首次提出。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用,且各層分治遞歸能夠同時進行。

歸併操做

歸併操做(merge),也叫歸併算法,指的是將兩個已經排序的序列合併成一個序列的操做。歸併排序算法依賴歸併操做。

迭代法

  1. 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
  2. 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
  3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
  4. 重複步驟3直到某一指針到達序列尾
  5. 將另外一序列剩下的全部元素直接複製到合併序列尾

遞歸法

原理以下(假設序列共有n個元素):

  1. 將序列每相鄰兩個數字進行歸併操做,造成floor(n/2)個序列,排序後每一個序列包含兩個元素
  2. 將上述序列再次歸併,造成floor(n/4)個序列,每一個序列包含四個元素
  3. 重複步驟2,直到全部元素排序完畢

特性:

最差時間複雜度:O(nlogn)

最好時間複雜度:O(n)

平均時間複雜度:O(n)

Python代碼的實現:

View Code

 


Quick(快速排序)

 

 維基百科:快速排序英語:Quicksort),又稱劃分交換排序partition-exchange sort),一種排序算法,最先由東尼·霍爾提出。在平均情況下,排序n個項目要大O符號)O(nlogn)次比較。在最壞情況下則須要O(n^2)次比較,但這種情況並不常見。事實上,快速排序一般明顯比其餘O(nlogn)算法更快,由於它的內部循環(inner loop)能夠在大部分的架構上頗有效率地被實現出來。

算法

 
快速排序採用「分而治之、各個擊破」的觀念,此爲原地(In-place)分區版本。

快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分爲兩個子序列(sub-lists)。

步驟爲:

  1. 從數列中挑出一個元素,稱爲"基準"(pivot),
  2. 從新排序數列,全部比基準值小的元素擺放在基準前面,全部比基準值大的元素擺在基準後面(相同的數能夠到任何一邊)。在這個分區結束以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做。
  3. 遞歸地(recursively)把小於基準值元素的子數列和大於基準值元素的子數列排序。

遞歸到最底部時,數列的大小是零或一,也就是已經排序好了。這個算法必定會結束,由於在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。

在簡單的僞代碼中,此算法能夠被表示爲:

 function quicksort(q)
     var list less, pivotList, greater
     if length(q) ≤ 1 {
         return q
     } else {
         select a pivot value pivot from q
         for each x in q except the pivot element
             if x < pivot then add x to less
             if x ≥ pivot then add x to greater
         add pivot to pivotList
         return concatenate(quicksort(less), pivotList, quicksort(greater))
     }

特性:

最差時間複雜度:O(n^2)

最好時間複雜度:O(n)或O(nlogn)

平均時間複雜度:O(n^2)

Python代碼的實現:

View Code

 


Selection(選擇排序)

選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工做原理以下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。

選擇排序的主要優勢與數據移動有關。若是某個元素位於正確的最終位置上,則它不會被移動。選擇排序每次交換一對元素,它們當中至少有一個將被移到其最終位置上,所以對n個元素的表進行排序總共進行至多(n-1)次交換。在全部的徹底依靠交換去移動元素的排序方法中,選擇排序屬於很是好的一種。

特性:

最差時間複雜度:O(n^2)

最好時間複雜度:O(n^2)

平均時間複雜度:O(n^2)

Python代碼的實現:

View Code

 


Shell(希爾排序)

維基百科:希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。希爾排序是非穩定排序算法。

希爾排序是基於插入排序的如下兩點性質而提出改進方法的:

  • 插入排序在對幾乎已經排好序的數據操做時,效率高,便可以達到線性排序的效率
  • 但插入排序通常來講是低效的,由於插入排序每次只能將數據移動一位

算法實現

原始的算法實如今最壞的狀況下須要進行O(n2)的比較和交換。V. Pratt的書對算法進行了少許修改,可使得性能提高至O(n log2 n)。這比最好的比較算法的O(n log n)要差一些。

希爾排序經過將比較的所有元素分爲幾個區域來提高插入排序的性能。這樣可讓一個元素能夠一次性地朝最終位置前進一大步。而後算法再取愈來愈小的步長進行排序,算法的最後一步就是普通的插入排序,可是到了這步,需排序的數據幾乎是已排好的了(此時插入排序較快)。

假設有一個很小的數據在一個已按升序排好序的數組的末端。若是用複雜度爲O(n2)的排序(冒泡排序插入排序),可能會進行n次的比較和交換才能將該數據移至正確位置。而希爾排序會用較大的步長移動數據,因此小數據只需進行少數比較和交換便可到正確位置。

一個更好理解的希爾排序實現:將數組列在一個表中並對列排序(用插入排序)。重複這過程,不過每次用更長的列來進行。最後整個表就只有一列了。將數組轉換至表是爲了更好地理解這算法,算法自己僅僅對原數組進行排序(經過增長索引的步長,例如是用i += step_size而不是i++)。

例如,假設有這樣一組數[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],若是咱們以步長爲5開始進行排序,咱們能夠經過將這列表放在有5列的表中來更好地描述算法,這樣他們就應該看起來是這樣:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

而後咱們對每列進行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

將上述四行數字,依序接在一塊兒時咱們獲得:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].這時10已經移至正確位置了,而後再以3爲步長進行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序以後變爲:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最後以1步長進行排序(此時就是簡單的插入排序了)。

特性:

最差時間複雜度:O(n^2)

最好時間複雜度:O(n)

平均時間複雜度:取決於步長

Python代碼的實現:

View Code

 


 

冒泡,插入,選擇排序的平均時間複雜度比較:

相關文章
相關標籤/搜索