算法時間複雜度和空間複雜度python
瞭解時間複雜度對算法的選用會頗有幫助,好比說以前怎麼樣選擇數據結構,都是經過每一個操做的時間複雜度的分析來看是否是知足需求,確定的是,在知足需求的狀況下,時間複雜度越優越好,操做次數越少越好。算法
大O是什麼?能夠理解爲操做次數與數據個數的比例關係;O(1)是有限次數的操做;O(n)是操做正比於你的元素。數組
大O表示法:數據結構
參考《算法導論》的列子:考慮計算一個n * n的矩陣全部元素的和:ide
列舉兩種方式:
函數
# version1 total_sum = 0 for i in range(n): row_sum[i] = 0 for j in range(n): row_sum[i] = row_sum[i] + matrix[i, j] total_sum = total_sum + matrix[i, j] # version2 total_sum = 0 for i in range(n): row_sum[i] = 0 for j in range(n): row_sum[i] = row_sum[i] + matrix[i, j] total_sum = total_sum + row_sum[i] # 注意這裏和上邊的不一樣
兩種方式的主要區別在最後一行,優化
第一個方式:假設矩陣是n*n的,這嵌套是在兩層循環裏面,並且每一步都循環n次,能夠認爲它是一個n*n的,循環兩次,即 (2n)*n的時間複雜度。spa
第二個方式:假設矩陣是n*n的,能看出最後一行不在上面的循環裏面,上面的循環執行了n*n(嵌套在兩層循環裏面),最後一行是執行n次,因此他是n*n+n的時間複雜度。orm
若是數據量很小,可能感受不出差別,可是若是放大n的增加的時候,總的操做次數就很明顯區別了:blog
一般不關係每一個算法執行了多少次,更關心隨輸入規模的增長算法運行的時間將以什麼樣的速度增長,因此定義了一個符號,大O符號。
4. 如何計算時間複雜度
上面舉例2個版本的計算矩陣和的代碼,有兩個公式:
① 2n * n = 2n2
② n+n*n = n+n2
當n很是大的時候,n*n(即n的平方)的數值將佔主導,能夠忽略單個n的影響:
n+n2<= 2n2
能夠認爲兩個算法的時間複雜度都爲O(n2)
5.經常使用的時間複雜度
列舉一些經常使用的時間複雜度,按照增加速度排序,平常咱們的業務代碼中最經常使用的是指數以前的複雜度,指數和階乘的增加速度很是快, 當輸入比較大的時候用在業務代碼裏是不可接受的。
O | 名稱 |
舉例 | 補充 |
1 | 常量時間 | 一次賦值 | nlogn如下的這些時間複雜度都是比較佔優點的。 |
logn | 對數時間 | 折半查找 | |
n | 線性時間 | 線性查找 | |
nlogn | 對數線性時間 | 快速排序 | |
n2 | 平方 | 兩重循環 | 越向上增加的越快那那怕是計算機很是快,依然要花不少時間運行。 |
n3 | 立方 | 三重循環 |
|
2n | 指數 |
遞歸求斐波那契數列 | |
n! | 階乘 | 旅行商問題 |
O(1) | 固定時間內的一次操做,好比:一次賦值,一次加法,幾回加法操做。 |
O(logn) | 二分查找,操做一個有序數組的時候,每次均可以把它折半。 |
O(n) | 查找都須要從頭查到尾,找到了才能退出。 |
O(nlogn) | 快速排序或歸併 |
O(n2) | 兩重循環嵌套 |
O(n3) | 三重嵌套 |
O(2n) | 指數就有一些遞歸算法,沒有優化的遞歸 |
O(n!) | 旅行商問題,學術界討論會比較多,工程會少一些 |
6.空間複雜度
相比於時間,空間不少時候,不是主要的考慮因素,用戶老爺們都等不及,並且如今存儲都愈來愈便宜了,爲了提高響應速度,能可多用一點空間,因此空間複雜度討論的少一些;固然,若是數據量很是很是大,也會考慮空間佔用的問題。
常見的空間複雜度的增加趨勢圖:
因此,工程上能接受的都是 nlogn 如下的空間複雜度,圖中nlogn,n,log2n這些。