常用數據結構操作與算法複雜度總結


博客:blog.shinelee.me | 博客園 | CSDN

時間複雜度

如何評估一個算法的計算時間?

一個算法的實際運行時間很難評估,當時的輸入、CPU主頻、內存、數據傳輸速度、是否有其他程序在搶佔資源等等,這些因素都會影響算法的實際運行時間。爲了公平地對比不同算法的效率,需要脫離開這些物理條件,抽象出一個數學描述。在所有這些因素中,問題的規模往往是決定算法時間的最主要因素。因此,定義算法的時間複雜度T(n)T(n),用來描述算法的執行時間隨着輸入規模的增長將如何變化,增長速度是怎樣的

在輸入規模較小時,運行時間本來就少,不同算法的差異不大。所以,時間複雜度通常關注的是輸入規模nn較大時運行時間的變化趨勢,稱之爲漸進複雜度,採用大O記號,表示漸進上界,對於任意的n>>2n >> 2,若有常數cc和函數f(n)f(n)滿足
T(n)cf(n) T(n) \leq c \cdot f(n)
則記作
T(n)=O(f(n)) T(n) = O(f(n))
可以簡單地認爲,O(f(n))O(f(n))表示運行時間與f(n)f(n)成正比,比如O(n2)O(n^2)表示運行時間與輸入規模的平方成正比,這樣講雖然並不嚴謹,但一般情況下無傷大雅

**在nn很大時,常數cc變得無關緊要,不同算法間的比較主要關注f(n)f(n)部分的大小。**比如,在n>>100n >> 100時,n2n^2要比100n100n大得多,因此重點關注n2n^2nn增長速度的差異即可。

不同時間複雜度的增長速度對比如下,圖片來自Big-O Cheat Sheet Poster

Big-O Complexity

除了大OO記號,還有大Ω\Omega記號和Θ\Theta記號,分別表示下界和確界,
Ω(f(n)): cf(n)T(n)Θ(f(n)): c1f(n)T(n)c2f(n) \Omega(f(n)) : \ c\cdot f(n) \leq T(n) \\\Theta(f(n)) : \ c_1 \cdot f(n) \leq T(n) \leq c_2 \cdot f(n)
他們的關係如下圖所示,圖片截自鄧俊輝-數據結構C++描述第三版

漸進複雜度不同記號關係

常用數據結構操作與算法的複雜度

下面彙總摘錄了常用數據結構操作和排序算法的複雜度,來源見引用。其中包含最壞時間複雜度、平均時間複雜度以及空間複雜度等,對於排序算法還含有最好時間複雜度。

Common Data Structure Operations

Graph and Heap Operations

array sorting algorithms

附帶上鍊接:

Array Stack Queue Singly-Linked List Doubly-Linked List Skip List Hash Table Binary Search Tree Cartesian Tree B-Tree Red-Black Tree Splay Tree AVL Tree KD Tree

Quicksort Mergesort Timsort Heapsort Bubble Sort Insertion Sort Selection Sort Tree Sort Shell Sort Bucket Sort Radix Sort Counting Sort Cubesort

以及 Data Structures in geeksforgeeks

輸入規模較小時的情況

漸進複雜度分析的是輸入規模較大時的情況,輸入規模較小時呢?

在輸入規模較小時,就不能輕易地忽略掉常數cc的作用,如下圖所示,圖片來自Growth Rates Review複雜度增長快的在輸入規模較小時可能會小於複雜度增長慢的

complexity growth rates

所以在選擇算法時,不能無腦上看起來更快的高級數據結構和算法,還得具體問題具體分析,因爲高級數據結構和算法在實現時往往附帶額外的計算開銷,如果其帶來的增益無法抵消掉隱含的代價,可能就會得不償失。

這同時也給了我們在代碼優化方向上的啓示,

  • 一是從f(n)f(n)上進行優化,比如使用更高級的算法和數據結構;
  • 還有是對常數cc進行優化,比如移除循環體中不必要的索引計算、重複計算等。

以上

引用

發佈了55 篇原創文章 · 獲贊 77 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章