1. 程式人生 > >算法分析 - 學習筆記

算法分析 - 學習筆記

算法設計 ron -a ase log 參考 尋找最大數 輸入 基本

這篇博文主要會講述基礎的算法分析,對於算法分析主要是針對算法運行時間進行分析。

幾個需要註意的讀法:Omega(Ω),Theta(Θ)和大O符號。

一、算法分析 - 最壞情況分析法

算法分析其實主要針對兩方面,但是平時更多地所講的一個算法的好壞通常是通過算法運行時間來衡量,如若一個算法運行時間短,則說明這個這個算法的針對某個問題的執行效率不錯,反之則說明算法較為低效。前面所說的算法針對運行時間衡量結果大部分指的更多是是效率問題,好壞非一個絕對的標準,針對不同問題,算法執行的時間也不同,並無法絕對說這個算法好還是那個算法好,基本要從實際出發。一般而言,我們所期望的是隨著輸入數量(input size: N)的成倍增長,算法運行效率應當僅慢常數因子c(constant factor c)

。而我們在分析算法時很多時候用的是最壞情況分析法(Worst-case Analysis),亦稱最壞情況運行時間(Worst-case Running Time)。而一個算法是有效率的(efficient)如果它的運行時間是多項式時間,也就是說針對某一個問題的算法運行時間不大於問題大小的多項式倍數。下圖是不同算法隨著輸入大小的增加所需要運行時間:

技術分享圖片

二、漸近增長階

假設算法的最壞情況運行時間我們記作T(n),這裏有另外一個函數f(n),如果存在下述的三種情況,我們則稱之為上界、下界和既是上界也是下界。

漸近上界:如果存在一個常數c > 0和n0 > 0以至於所有n > n0 都有T(n) < c · f(n),我們則稱之為T(n)是O(f(n)),f(n)為T(n)的上界。

舉個例子:假設我們有一個算法的運行時間為T(n) = pn2 + qn + r,這裏的p、q和r都是大於0的數,那麽如果我想說這個函數是服從O(n2)的話,則可以寫成T(n) = pn2 + qn + r ≤ pn2 + qn2 + rn2 ≤ (p + q + r) · n2 ,這個則符合上述定義。因此我們稱T(n)是O(n2) 。

漸近下界:反之,對於任意大的輸入,如果存在一個函數f(n)致使T(n) ≥ ε · f(n)(亦稱之為Ω(f(n))),我們則稱之為漸近下界。

舉個例子:T(n) = pn2 + qn + r ≥ pn2 ≥ pn(p = ε),所以T(n)是Ω(n),也就是f(n) = n是T(n)的下界。

既是上界也是下界:從上面兩個式子我們可以看出f(n) = n2 是T(n)的上界也是下界,我們稱之為Θ(n2)。

三、例子

這裏主要列舉幾個算法來表述不同的運行時間。

3.1 線性時間(linear time)

線性時間指的是算法的運行時間最多為一個常數因子乘於輸入的大小,最常用來表示的一個算法就是查找一個數列中的最大數及合並兩個已經排好序的數列,這裏僅展示偽代碼,因為實現都較為簡單,可以嘗試用自己喜歡的語言復現。

# 尋找最大數
max <- a1
for i = 2 to n:
    if ai > max:
        max = ai

# 合並兩個排好序的數
i = 1, j = 1
final_output = []
while (both list are not empty):
  if ai <= bj:
    final_output.append(ai)
    i += 1
  else:
    final_output.append(bj)
    j += 1
final_output.append(remainder of the nonempty list)

3.2 對數時間(n log (n)) - 歸並排序(此處是Python代碼實現)

def MergeSort(lst):

	if len(lst) == 1:
		return lst

	half_length = len(lst) // 2
	left_lst = MergeSort(lst[:half_length])
	right_lst = MergeSort(lst[half_length:])

	return Merge(left_lst, right_lst)

def Merge(left_lst, right_lst):
	"""Merge Function for Merge Sort"""
	l_index, r_index = 0, 0
	lst = []
	while l_index < len(left_lst) and r_index < len(right_lst):
		if left_lst[l_index] < right_lst[r_index]:
			lst.append(left_lst[l_index])
			l_index = l_index + 1
		else:
			lst.append(right_lst[r_index])
			r_index = r_index + 1
	lst = lst + left_lst[l_index:]
	lst = lst + right_lst[r_index:]
	return lst 

還有關於O(n2)、O(n3)等其他的運行時間的例子,此處就不一一舉例,有興趣的朋友可以參考下面的列出的書籍並按照自己喜歡的編程語言實現一遍。

如若有哪裏講的不對或者讀者有更好的建議,歡迎指出,非常感謝!

參考:

《算法設計》,Jon Kleinberg / éva Tardos,清華大學出版社,2007。

算法分析 - 學習筆記