《數據結構與算法》——O(3N)=O(N) ?

上帝的磨盤轉動很慢,但是卻磨得很細。 ——毛姆

本文已經收錄至我的GitHub,歡迎大家踊躍star 和 issues。

github.com/midou-tech/…

數據結構的基本概念

數據結構

相互之間存在一種或多種特定關係的數據元素的集合,我總結一下就是描述數據關係的一種載體。

數據結構包括邏輯結構和存儲結構兩個層次的描述。

邏輯結構

描述數據邏輯關係的一種方式,與數據的存儲無關。邏輯結構中數據元素之間的關係主要分爲四種:集合結構、線性結構、樹結構、圖結構。所有的數據結構在邏輯上都可以用這四種中的一種。

存儲結構

數據和數據元素邏輯關係的存儲對象,也被稱爲物理結構。通常邏輯結構包含兩種,鏈式存儲和順序存儲。順序存儲 數據元素存儲在一塊連續的內存空間上,例如數組,就是一塊連續的空間。鏈式存儲 數據存儲不一定在一塊連續的內存空間上,例如單鏈表。

數據類型

是一組值的集合和定義在這個集合上的操作的總稱。

抽象數據類型

由用戶定義的表示應用問題的數學模型,以及定義在這個模型上的一組操作的總稱,具體包括三部分,數據對象、數據對象上關係的集合以及對數據對象基本操作的集合。

抽象數據類型有自己的定義格式:

1ADT 抽象數據對象名 {
2  數據對象:(數據對象的定義)
3  數據關係:(數據關係的定義)
4  基本操作:(基本操作的定義)
5}
複製代碼

算法與數據結構

算法 解決一類問題而規定的一個有限長操作序列。

算法必須滿足幾個特性才能稱之爲算法:

  • 有窮性:算法執行必須是在有限的步數之後完成,執行每一步也是有限的時間。簡單來說就是執行一個算法時間是有限,總不能執行一個算法和時間同步沒有盡頭吧。
  • 確定性:算法每種執行操作都是確定的,執行結果也是確定的,沒有二義性的。算法的執行者和閱讀者都明確其算法含義和如何執行。
  • 可行性:這個理解起來很簡單,算法被設計出來是可以被計算機完成的。
  • 輸入&輸出:一個算法一定是有輸入和輸出的,輸入是算法執行的條件,輸出是算法產生的結果。

算法優劣的評價標準

評價算法優劣的主要從以下幾個方面考慮:

  • 正確性:在合理的數據輸入下,能夠在有限的運行時間內得到正確的結果。
  • 可讀性:包括兩個方面一個是研究算法的人們易與讀寫,另一個是執行算法的機器可以執行。
  • 健壯性:對於非法輸入,好的算法是會做相應的處理而不是產生一些奇怪的結果。
  • 高效性:高效性包括時間和空間兩個方面,在保證算法結果正確的情況下,時間上花費的越少,空間上花費的越少,算法就很高效。現實中往往是二者不可兼得,很多算法都是時間上優越,空間上浪費,還有很多算法反正。
時間複雜度

用算法中的"基本語句" 的執行次數來度量算法的工作量。正常狀態下一般用循環或者遞歸的運行次數。

在某些算法中算法的時間複雜度會根據算法的初始狀態決定,這種時候需要計算出算法的最好時間複雜度、最壞時間複雜度和平均時間複雜度。比如常見的排序算法就有最好最壞和平均時間複雜度。

空間複雜度

算法在運行過程中佔用的輔助空間大小,被稱作該算法的空間複雜度。

時間複雜度和空間複雜度都是用大寫的 "O" 表示。對於一個算法,其時間複雜度和空間複雜度往往是相互影響的,當追求一個較好的時間複雜度時, 可能會導致佔用較多的存儲空間, 即可能會使空間複雜度的性能變差, 反之亦然。不過, 通常情況下, 鑑於運算空間較爲充足, 人們都以算法的時間複雜度作爲算法優劣的衡址指標。

自己在寫算法時一定要可以去留意算法的效率問題,不然你寫出來的算法雖然滿足可行性、確定性、健壯性,也會是一個很爛的算法。時間複雜度是我們日常編程設計考慮最多的。

在學習算法效率的時候一般會把O(3N)≈O(N),N的常數倍都直接約等於O(N)。這也是約等於,不是完全相等。實際編程設計時特別是在一些效率要求較高的程序設計一定要考慮進去,不能約等於。在高併發的請求下,O(3N)和O(N)是有着天壤之別的。

我在工作中遇到的一個實例,差點背了事故。一個高併發的場景下(qps在5k左右),我寫了一個O(3N)的程序,測試時邏輯沒問題,結果沒問題,沒有對該場景進行高併發壓測,就上線了。上線之後不到十分鐘我收到短信報警,多臺機器CPU打滿了,內存也在飆升(32C—124G的服務器)。此時的我嚇壞了,意識到我剛剛發佈了,肯定和我發佈有關。保證線上優先,立馬把剛上線的服務下掉,別影響其他業務正常。下掉我的服務,CPU資源報警解除了。

經過一番review代碼,各種測試,最終定位到兩個問題。一個是我代碼裏面有一處內存泄漏導致內存飆升了,還有一處就是時間複雜度的問題。錯誤的把O(3N)=O(N)的算法上線了。把算法優化爲O(N)之後,經過一番壓力測試完全沒問題。這次事件對我一個很大的啓示是,高併發的場景下,O(3N)≠O(N),一定不能等於

高併發場景下算法的效率尤爲重要,此時時間和空間的平衡關係一定要充分考慮。

總結

概念性的東西一般在實際工作中不會去過多糾結,很多工作很久的同學完全不記得這些概念的文字卻依然可以輕鬆愉快的完成相應知識的工作。是的,不拘泥於概念,卻熟練運用概念對應的知識是我們的目的。這樣說並不是概念不重要,完全不需要看概念。概念是認識一個事物的開始,他表示一個事物是什麼,後面的做什麼,爲什麼,都是建立在是什麼的基礎上的,所以概念一定要理解,而不是背書

在學校的同學會養成一種很不好的習慣,就是必須去記這些概念。爲什麼呢?因爲考試會考。是的,我在大學的時候也會去記這些概念的文字應付考試。比如下面這些考題就曾經出現在考卷中

  • 簡述下列概念:數據、數據元素、數據項、數據對象、數據結構、邏輯結構、存儲結構、

    抽象數據類型。

不要慌,理解記憶這些概念。既能應付考試,又能很好的理解知識。你需要記住考試好不代表你對知識掌握的好,掌握是指的能把這些知識運用在實際工作和生活應用中。

下一篇文章會寫數據結構一種非常重要的數據結構——線性表。記得關注我,精彩內容不錯過喔。

微信搜索 龍躍十二 即可訂閱,微信更新會早於博客喔。

本文同步分享在 博客“龍躍十二”(JueJin)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章