3.常見時間複雜度計算舉例
空間複雜度
時間複雜度和空間複雜度的求解可以說是所有資料結構初學者所面對的第乙個重點,它是衡量一段**優劣的重要指標。本篇文章博主會詳細的向大家介紹求解一段**時間複雜度和空間複雜度的方法,並且會舉例來說明,希望大家能夠靜下心慢慢的看完,相信一定會對大家帶來幫助。
剛剛我提到過,時間複雜度和空間複雜度是衡量一段**優劣的重要指標,其實主要影響的就是演算法的效率,所以接下來我想先請大家了解一下演算法效率的概念。
演算法效率分析分為兩種:第一種是了解完演算法效率的概念之後,接下來我們就來看看時間複雜度是如何求解的。時間效率
,第二種是空間效率
。時間效率被稱為時間複雜度,而空間效率被稱作空間複雜度。時間複雜度主要衡量的是乙個演算法的執行速度,而空間複雜度主要衡量乙個演算法所需要的額外空間,在計算機發展的早期,計算機的儲存容量很小。所以對空間複雜度很是在乎。但是經過計算機行業的迅速發展,計算機的儲存容量已經達到了很高的程度。所以我們如今已經不需要再特別關注乙個演算法的空間複雜度。
在電腦科學中,演算法的時間複雜度是乙個函式(這裡指的是數學上的函式),他定量描述了該演算法的執行時間。乙個演算法執行所耗費的時間,從理論上說,是不能算出來的,只有你把程式放在機器上跑起來,才能知道。但是我們需要每個演算法都上機測試嗎?是可以都上機測試,但是這很麻煩,所以才有了時間複雜度這個分析方式。乙個演算法所花費的時間與其中語句的執行次數成正比例,演算法中基本操作的執行次數
,為演算法的時間複雜度。
問:請計算一下func1基本操作執行了多少次?
void
func1
(int n)
}for
(int k =
0; k <
2* n;
++k)
int m =10;
while
(m--
)printf
("%d\n"
, count)
;}
func1執行的基本操作次數:f(n) = n² + 2*n + 10n = 10 f(n) = 130
n = 100 f(n) = 10210
n = 1000 f(n) = 1002010
實際上我們計算時間複雜度的時候,其實並不一定要計算精確的執行次數
,而只需要大概執行次數,那麼這裡我們使用大o的漸進表示法。
大o符號(big o notation):是用於描述函式漸進行為的數學符號。使用大o漸進表示法以後,根據規則第二點只保留最高項,func1的時間複雜度為:o(n²)
n = 10 f(n) = 100
n = 100 f(n) = 10000
n = 1000 f(n) = 1000000
通過上面我們會發現大o的漸進表示法去掉了那些對結果影響不大的項,簡潔明瞭的表示出了執行次數。
最壞情況:任意輸入規模的最大執行次數(上界)
平均情況:任意輸入規模的期望執行次數
最好情況:任意輸入規模的最小執行次數(下界)
例如:在乙個長度為n的陣列中搜尋乙個資料x
最好的情況:1次找到
最壞的情況:n次找到
平均情況:n/2次找到
在實際情況中時間複雜度的估算實際上是一種悲觀的估算,關注的是演算法的最壞運**況
,所以陣列中搜尋資料的時間複雜度複雜度為o(n)。
// 計算func2的時間複雜度?
void
func2
(int n)
int m =10;
while
(m--
)printf
("%d\n"
, count)
;}
本段**基本執行操作是2n+10次,根據推導大o階方法,只保留最高端並且去除與這個專案相乘的常數,時間複雜度為o(n)
// 計算func3的時間複雜度?
void
func3
(int n,
int m)
for(
int k =
0; k < n;
++k)
printf
("%d\n"
, count)
;}
本段**基本執行操作是m + n次,因為m和n是兩個未知數,所以時間複雜度為o(m + n).
這裡多提一點,如果告訴m遠大於n,那麼此時的時間複雜度就為o(m),因為時間複雜度就是乙個估算的過程。
// 計算func4的時間複雜度?
void
func4
(int n)
printf
("%d\n"
, count)
;}
本段**基本執行次數為100次,100是乙個常數,根據推導大o階方法,用常數1取代常數,時間複雜度為o(1)。
// 計算strchr的時間複雜度?
const
char
*strchr
(const
char
* str,
int character)
;
這裡簡單介紹一下strchr函式,這個函式是在乙個字串中查詢乙個字元。
這樣的話基本執行操作次數最好的情況是1次直接找到,最壞的情況是n次遍歷完整個字串才找到,而時間複雜度關注的是最壞的情況,故時間複雜度為o(n)。
// 計算斐波那契遞迴fibonacci的時間複雜度?
long
long
fibonacci
(size_t n)
這道題如果僅僅看函式的話是分析不出來的,這裡需要畫圖來分析。
總共的呼叫次數應該是1+21+22+···+2(n-2)+2(n-1)-空掉部分 = 2n - 1 - 空掉部分。因為有的地方會提前算到1而結束,所以必須減掉一部分。
根據推導大o階方法,最終的時間複雜度應該是o(2^n)。
介紹這道題的主要目的是想告訴大家,在求解時間複雜度的時候千萬不要僅僅抱著**在那啃。要知道很多複雜程式的時間複雜度光用眼睛看**是看不出來的,畢竟人腦是有限的,所以需要自己動手畫圖,這樣才能看清楚程式到底執行了多少次數,因此大家一定要養成勤動手畫圖的好習慣。
時間複雜度的求解就介紹到這裡,下面我們再一起來看空間複雜度的求解。
空間複雜度是對乙個演算法在執行過程中臨時占用儲存空間大小的量度。空間複雜度不是程式占用了多少位元組的空間,因為這個也沒太大意義,所以空間複雜度算的是變數的個數
。空間複雜度計算的規則基本跟時間複雜度類似,也使用大o漸進表示法
。
// 計算bubblesort的空間複雜度?
void
bubblesort
(int
* a,
int n)}if
(exchange ==0)
break;}
}
這是一段實現氣泡排序的**,**共開闢了5個變數為常數,根據大o漸進法,空間複雜度為o(1)。
所以大家在做題的時候,如果題目要求空間複雜度是o(1),你可千萬不要理解為只能建立乙個變數,o(1)的含義是所建立的變數個數必須為常數。
// 計算fibonacci的空間複雜度?
long
long
*fibonacci
(size_t n)
return fibarray;
}
這段**實現的功能是將前n個斐波那契數存放在乙個動態開闢的陣列中。
動態記憶體開闢了n個變數,空間複雜度為o(n)。
空間複雜度的例子就介紹這兩個,實際上現在除了在嵌入式開發這類特殊情況下,其他開發的過程中最看重還是對時間複雜度的要求,因為現在記憶體的發展程度已經很高了,人們在開發的時候往往會犧牲空間而換取時間效率。不過兩種複雜度求解的方法我們都應該熟練的掌握,千萬不能偷懶啊。
演算法複雜度 時間複雜度和空間複雜度
1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且乙個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數...
演算法複雜度 時間複雜度和空間複雜度
演算法複雜度 時間複雜度和空間複雜度 關鍵字 演算法複雜度 時間複雜度 空間複雜度 1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時 間多,哪個演算法花費的時間少就可以...
演算法複雜度 時間複雜度和空間複雜度
演算法的時間複雜度是指執行演算法所需要的計算工作量。n稱為問題的規模,當n不斷變化時,時間頻度t n 也會不斷變化。但有時我們想知道它變化時呈現什麼規律。為此,我們引入時間複雜度概念。一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用t n 表示,若有某個輔助函式f n 存在乙個正...