今天突然想到了乙個問題:讓你立即把堆排、快排等等排序演算法寫出來會不會,並且不能犯邏輯錯誤?
我說:不會,至少需要思考一下,並且可能還需要時間除錯。
排序演算法應是作為最基本的工具一樣,是信手捏來的,所以我把《演算法導論》上的幾個排序問題看了並且實現了一遍;在此做分享:
氣泡排序:
氣泡排序應該算是比較簡單並且使用廣泛的排序演算法之一了吧,但是它的效率並不怎麼高,我們可以先看一下實現:
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 錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素列已經排序完成。穩定性 氣泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交...