什麼是演算法
我想很多程式設計師恐怕誤解了「演算法」的意義,一想到演算法就是動態規劃,機器學習之類的高大名詞。演算法其實就是數學中的「解題過程」,解題過程要求精確,考慮各種情況,需要人看得懂。演算法不需要你在鍵盤上選擇什麼程式語言實現,只需要在本子上詳細的寫出每乙個步驟就可以了。
演算法真的很重要嗎?
我經常在社群裡看到有人說初級開發不需要懂演算法,這是非常真切的,很多的業務構建都是很常規的套路,查個資料庫返回,沒有太多複雜的計算,哪需要什麼解題過程。
但是我想遇到稍微複雜一點的業務,或者想要系統執行得更流暢、更有效能的時候,我們就會構思採取什麼樣的方法能讓系統跑得更快、更穩定,於是有了「分布式演算法」等架構方面的演算法。有時候我們發現某個響應很慢,可能就是某個演算法的執行效率過慢,只是我們不知道這也能稱為演算法?最常見的恐怕是多層遍歷,很容易導致效率很低的問題。所以在程式設計的時候要養成思考演算法複雜度的習慣。
演算法對於提高**的執行效率,對問題的抽象有非常大的幫助。演算法學好了,在遇到同一類問題的時候再也不用擠破腦袋來想了,能夠更加容易的聯想到相關的演算法解決問題。程式設計師要想程式設計更容易,不怕各種場景沒遇到過,學好演算法是很有必要的。
排序演算法的運用非常廣泛。各種語言都有自己內建的排序函式,在面試過程中也經常會有排序演算法的考題。總結幾種排序演算法的實現。
這個問題的顯示表示是:請詳細描述如何將一組數字按從小到大的順序排列。
我首先想到的是:
找出陣列中最小的乙個;
把這個數放到另一陣列的最後面;
把這個數從原來的陣列中剔除;
重複 重複的過程通常涉及到遍歷和遞迴,上面這個解法叫「選擇排序」,用 python 實現如下:
def select_sort(arr):
new_arr =
# 重複
for i in range(len(arr)):
small_index = find_smallest(arr)
# 把這個數從原來的陣列中剔除;
smallest = arr.pop(small_index)
# 把這個數放到另一陣列的最後面;
return new_arr
def find_smallest(arr):
"""找出陣列中最小的乙個;"
"" smallest = arr[0]
index = 0
for e in range(1,len(arr)):
if arr[e] < smallest:
smallest = arr[e]
index = e
return index
複製**
可以看出來,**實現基本上就是用程式語言寫出解題思路。所以很多程式設計高階書都提到乙個解決問題的辦法就是離開鍵盤,去上個廁所,在紙上畫一畫。只要是解題思路很詳細,基本上是可以用來當偽**使用的,可以全部放入**的注釋當中。
氣泡排序(bubble sort)
比較前乙個數和後乙個數,如果前比後大,對換他們的位置;
迴圈執行
def bubble_sort(arr):
for i in range(len(arr) - 1):
for j in range(len(arr) - i - 1):
if arr[j] > arr[j + 1]:
tmp = arr[j + 1]
arr[j + 1] = arr[j]
arr[j] = tmp
return arr
複製**
快速排序
上面兩種演算法要操作的步驟很多,當陣列太多時就會造成效能過低,我們可以想辦法減少要操作的步驟,從而降低演算法的複雜度,提高執行效率。減少步驟的很多演算法都是將資料分成幾部分來處理,也就是通常說的「分治」,從而不斷減少沒部分需要處理的步驟,選擇排序就是這樣一種演算法: 1.選出第乙個元素 2.遍歷每個元素,也就是從第二個開始拿,如果比第乙個元素小,放到乙個新陣列裡;如果比它大,放到另乙個陣列; 3.對兩個新陣列執行同樣的操作; 那什麼時候不需要執行這樣的操作了呢?當陣列的元素個數小於2的時候,不需要比較了,分治策略就結束。
「分治」是一種非常常見的解題思路。因為它能不斷的將問題變成更簡單的問題,最後變成乙個顯而易見的事。也就是說它有兩個條件:
分治法在演算法中非常普遍,不是因為他能降低演算法的複雜度,而是他能一步步將複雜的問題變得越來越簡單,規模越來越小,最後變成乙個超級簡單的問題,如果能進一步抽象這種過程,就能考執行同樣的抽象步驟解出來來。分治法經常和遞迴用在一起,這就衍生了一種變成方式——函式式程式設計,如果能多接觸一些遞迴的案例,對於函式式變成和抽象是非常有幫助的。軟體設計就是講乙個非常複雜的問題抽象的過程,所以掌握函式式程式設計和遞迴概念對於抽象能力和軟體設計應該是很有幫助的。
下面實現快速排序:
def quick(arr):
if len(arr) < 2:
return arr
else:
base = arr[0]
less = [i for i in arr[1:] if i < base]
greater = [i for i in arr[1:] if i >= base]
return quick(less) + [base] + quick(greater)
複製**
歸併排序
歸併排序和選擇排序一樣是一種分治遞迴策略:
從中間分成兩組
將兩個已經排序好的列表進行合併,合併成的列表就是排序好的 那怎麼對上述兩個列表排序呢?對兩個列表再執行分組策略 什麼時候不能繼續了呢?當元素個數小於 2 的時候
具體實現:
def merge_sort(arr):
# divide to two
if len(arr) < 2:
return arr
mid = int(len(arr)/2)
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result =
j = 0
i = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
i += 1
else:
j += 1
# add the larger part both left and right
result += left[i:]
result += right[j:]
return result
複製**
總結
這篇文章總結了 4 個常用的排序演算法的實現,這幾個演算法經常在面試中可以用到,需要牢牢掌握。掌握基礎演算法能讓程式設計師知道一些常用的設計套路,在真遇到這些演算法的應用場景的那一天,不至於撓頭不知所措。常用的演算法的複雜度能讓我們把握程式設計的效能,在軟體出現效能瓶頸的時候能通過改善軟體的演算法來優化。在文章中,我還說明了遞迴和函式式程式設計的重要性,軟體設計是乙個抽象的過程,面向流程的程式設計很難讓人養成抽象性思維,而函式式程式設計往往通過遞迴能將具體的問題進一步抽象,有助於培養我們的軟體設計能力,這恐怕是以前的大牛和黑客都特別崇尚 lisp 的原因。
幾種常用的排序演算法
介紹 快速排序是由東尼 霍爾所發展的一種排序演算法。在平均狀況下,排序 n 個專案要 n log n 次比較。在最壞狀況下則需要 n 2 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 n log n 演算法更快,因為它的內部迴圈 inner loop 可以在大部分的架構上很有效率地被實...
幾種常用的排序演算法
介紹 快速排序是由東尼 霍爾所發展的一種排序演算法。在平均狀況下,排序 n 個專案要 n log n 次比較。在最壞狀況下則需要 n 2 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 n log n 演算法更快,因為它的內部迴圈 inner loop 可以在大部分的架構上很有效率地被實...
幾種常用的排序演算法
size large 按照排序過程中所使用的內外存情況不同,可把排序分為內排序和外排序兩大類 若排序過程全部在記憶體資料表 如陣列 中進行,則成為內排序,若排序過程需要不斷地進行記憶體陣列和外村檔案之間的資料交換,則成為外排序。對於大的資料檔案,由於記憶體限制不能一次裝入記憶體進行排序,只能進行外排...