若干排序演算法的Python實現方法及原理

2021-08-14 20:08:11 字數 4627 閱讀 7722

今天突然想到了乙個問題:讓你立即把堆排、快排等等排序演算法寫出來會不會,並且不能犯邏輯錯誤?

我說:不會,至少需要思考一下,並且可能還需要時間除錯。

排序演算法應是作為最基本的工具一樣,是信手捏來的,所以我把《演算法導論》上的幾個排序問題看了並且實現了一遍;在此做分享:

氣泡排序

氣泡排序應該算是比較簡單並且使用廣泛的排序演算法之一了吧,但是它的效率並不怎麼高,我們可以先看一下實現:

def bubblesort(a):

length = len(a);

for i in range(0, length):

for j in range(length - 1, i, -1):

if a[j] < a[j - 1]:

(a[j], a[j - 1]) = (a[j - 1], a[j]);

return a;

a = [5, 0, 1, 3, 6, 2, 4, 9, 12, 11, 18, 20, 7, 8, 19, 13, 14, 17, 16, 10];

a = bubblesort(a);

print(a);

顧名思義,氣泡排序就像泡沫一樣一層一層往上冒,需要乙個乙個比較;

比較次數(n-1)*n / 2, 資料交換次數最壞情況3*(n-1)*n/2,最好情況0,所以其時間複雜度o(n^2);

插入排序

def insertionsort(a):

for i in range(1, len(a)):

key = a[i];

j = i - 1;

while (j >= 0) and (a[j] > key):

a[j + 1] = a[j];

j = j - 1;

a[j+1] = key;

return a;

a = [5, 0, 1, 3, 6, 2, 4, 9, 12, 11, 18, 20, 7, 8, 19, 13, 14, 17, 16, 10];

a = insertionsort(a);

print(a);

要理解插入排序,可以想象打撲克的時候是怎麼拿牌的,我們摸一張牌,然後從左往右(或從右往左)按順序比較,再把牌插入相應位置,插入排序就是這種思想。

時間複雜度o(n^2)

歸併排序

記得大二學習《資料結構》第一次寫這個演算法的時候想了好久,因為使用遞迴的思想,有些地方總是轉不過彎來。

def merge(a):

length = len(a);

if length <= 1 : return a;

n1 = length / 2;

n2 = length - n1;

l = ;

r = ;

for i in range(0, n1):

for i in range(0, n2):

if n1 > 1 : merge(l);

if n2 > 1 : merge(r);

i = 0;

j = 0;

for k in range(0, length):

if l[i] < r[j]:

a[k] = l[i];

i = i + 1;

if i >= n1:

for i in range(j, n2):

k = k + 1;

a[k] = r[i];

break;

else:

a[k] = r[j]

j = j + 1;

if j >= n2:

for j in range(i, n1):

k = k + 1;

a[k] = l[j];

break;

return a;

a = [5, 0, 1, 3, 6, 2, 4, 9, 12, 11, 18, 20, 7, 8, 19, 13, 14, 17, 16, 10];

a = merge(a);

print(a);

如果你能很好的理解遞迴的思想的話,想必歸併排序也是很簡單的。其核心思想在於怎麼把問題分解成一系列型別一樣的小問題。我們可以這樣想:

兩個排好序的數列怎麼合併成乙個序列?

兩個序列的資料乙個乙個比較,將小的存入新的佇列,直至這兩個數列乙個為空,則將另外乙個數列剩餘資料插入佇列。如果你把這兩個數列想象成撲克的話或許更好理解。如果這兩個序列都只有乙個資料的話,是不是會很簡單的就排完了?

[1, 3, 5], [2, 4, 6, 7]  *****=> [1, 2, 3, 4, 5, 6, 7]

歸併排序通過遞迴方法,最終將乙個待排序序列換成若干組待排序的包含乙個資料的數列。

時間複雜度o(nlog(n))

堆排序

曾經,第一次寫堆排,用c鍊錶,自信滿滿地構建了一顆二叉樹!原來堆排序不需要構建一顆視覺上的二叉樹!!!運用原址排序(只操作下標和對應的元素)解決!!!

parent = lambda i : (i -  1) / 2;

left = lambda i : 2 * i + 1;

right = lambda i : 2 * i + 2;

exchange = lambda a, b : (b, a);

def maxheapfy(a, i, length):

l = left(i);

r = right(i);

if l < length and a[l] > a[i]:

large = l;

else:

large = i;

if r < length and a[r] > a[large]:

large = r;

if large != i:

(a[i], a[large]) = exchange(a[i], a[large]);

maxheapfy(a, large, length);

return a;

def buildheap(a, length):

for i in range(length / 2 - 1, -1, -1):

maxheapfy(a, i, length);

def heapsort(a):

length = len(a);

buildheap(a, length);

for i in range(len(a) - 1, 0, -1):

(a[0], a[i]) = exchange(a[0], a[i]);

length = length - 1;

maxheapfy(a, 0, length);

return a;

a = [5, 0, 1, 3, 6, 2, 4, 9, 12, 11, 18, 20, 7, 8, 19, 13, 14, 17, 16, 10];

a = heapsort(a);

print(a);

堆排的思想在於理解最大(小)堆的概念:對於乙個二叉樹,父節點總是不小(大)於子節點的,即

a[parent(i)] >= a[i]......①

後面便於稱述不過於冗餘,只討論最大堆。

所以堆排的第一目的是建立乙個滿足條件的最大堆,要建立最大堆,就需要有最大堆的判定條件,即①式。建立最大堆之後,將根節點找到、儲存並剔除、對剩下的序列繼續做最大堆,重複上述過程即可完成排序。

時間複雜度o(nlog(n))

快速排序

注意也是原址排序!!!

def partition(a, p, r):

x = a[r];

i = p - 1;

for j in range(p, r):

if a[j] <= x:

i = i + 1;

(a[i], a[j]) = (a[j], a[i]);

(a[i + 1], a[r]) = (a[r], a[i + 1]);

return i + 1;

def quicksort(a, p, r):

if p < r:

q = partition(a, p, r);

quicksort(a, p, q - 1);

quicksort(a, q + 1, r);

return a;

a = [5, 0, 1, 3, 6, 2, 4, 9, 12, 11, 18, 20, 7, 8, 19, 13, 14, 17, 16, 10];

a = quicksort(a, 0, len(a) - 1);

print(a);

快排的思想在於將序列分成三部分a[0,i-1],a[i],a[i+1,n],並且滿足條件a[0, i-1]中所有元素小於等於a[i],a[i+1,n]中所有元素大於等於a[i]。同樣可以使用遞迴的方法實現。不理解的可以參考歸併排序。

時間複雜度o(nlog(n))

排序演算法python實現

先列出一些演算法複雜度的識別符號號的意思,最常用的是o,表示演算法的上屆,如 2n2 o n2 而且有可能是漸進緊確的,意思是g n 乘上乙個常數係數是可以等於f n 的,就是所謂的a b。而o的區別就是非漸進緊確的,如2n o n2 o n2 確實可以作為2n的上屆,不過比較大,就是所謂的a其他符...

python排序演算法實現

coding utf 8 氣泡排序 氣泡排序演算法的運作如下 比較相鄰的元素。如果第乙個比第二個大 公升序 就交換他們兩個。對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。針對所有的元素重複以上的步驟,除了最後乙個。持續每次對越來越少的元素重複上面的步...

Python實現排序演算法

一.氣泡排序 該排序重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果順序 如從大到小 首字母從z到a 錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素列已經排序完成。穩定性 氣泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交...