#####廢話的開始#####,從今天開始,可能就會多一個話題了,雖然以前在學校也學過數據結構這門課程,但是作為新世紀的90后,還是把學到的東西原原本本還給了老師,有借有還再借不難。其實后續也陸陸續續學習過,但是沒有去做很好總結,容易忘記,畢竟作為一個半路出家的碼農來說,這個需要好好學習,主要是沒怎么寫代碼,所以基本沒用到這些,就算寫了代碼,好像也用的不多,除非是從事底層開發的小伙伴,不過學會了這個數據結構和算法還是有有很多好處的,具體怎樣,請繼續往下看。
為什么要寫一個數據結構和算法的相關的介紹呢?學這個前至少也要知道自己為什么要學這個東西吧,學好了可以干嘛,可以怎么去學習。此文只是為了更好的從全局去了解數據結構和算法,為后期的學習做一個認知,做一個全局的認知后,對后期的學習會更好,會更加的系統,更加的鞏固,對於數據結構和算法的介紹所以也是很重要的,因為我們每做一件事情之前都要知道做這件事的目的,能夠帶來什么好處,怎么去做,用什么方式做的更好更有效率。不說別的吧,就說對於面試就很有用,看java的源碼也有用,越是接觸到底層的代碼,就越能體現數據結構和算法的重要性。如果你只是滿足於調用封裝好的代碼,那就到此為止,沒必要往下看,如果想好好的了解數據結構和算法,就認真的往下看,什么是數據結構和算法,有什么用,有什么魅力。
一、為什么要學數據結構和算法?
其實只要作為一個碼代碼的程序員來說,寫程序的都需要學這個,畢竟:程序 = 數據結構 + 算法 + 程序設計語言
數據結構和算法是程序的靈魂啊,失去靈魂的程序肯定是沒精神氣的(臃腫,速度慢,消耗資源多)
裝逼!強行裝逼!!強行一起吹水!!!這點很重要,其實下面的才是重點:
- 算法鍛煉自己的邏輯思維;
- 提升代碼性能,節省空間復雜度和時間復雜度
- 能夠在學習的過程中看的懂源碼,能夠在什么場景下知道選用更有的算法方案
- 找工作面試,有的甚至要現場寫代碼,升職加薪
- 一流的程序員搞算法,二流的程序員搞架構,三流的程序員搞業務;
- 很多時候根據公司的場景可以有選擇性的時間換空間或者空間換時間,這樣就增加了選擇
- 更好的理解應用軟件和框架,很多知名軟件和框架中都大量用了數據結構算法,比如mysql的索引用了b+樹,redis的list底層用了跳躍表,理解這些數據結構能更好的幫助我們理解使用這些軟件
總之,很重要!很重要!!真的很重要!!!
二、數據結構和算法是什么?
2.1、數據結構介紹
數據結構就是把數據組織起來,為了更方便地使用數據我們為了解決問題,需要將數據保存下來,然后根據數據的存儲方式來設計算法實現進行處理,那么數據的存儲方式不同就會導致需要不同的算法進行處理。我們希望算法解決問題的效率越快越好,於是我們就需要考慮數據究竟如何保存的問題,這就是數據結構。
數據結構可分為:線性結構和非線性結構。
線性結構:
- 線性結構作為最常用的數據結構,其特點是數據元素之間存在一對一的線性關系
- 線性結構有兩種不同的存儲結構,即順序存儲結構(數組)和鏈式存儲結構(鏈表)。順序存儲的線性表稱為順序表,順序表中的存儲元素是連續的
- 鏈式存儲的線性表稱為鏈表,鏈表中的存儲元素不一定是連續的,元素節點中存放數據元素以及相鄰元素的地址信息
- 線性結構常見的有:數組、隊列、鏈表和棧.
非線性結構:
非線性結構包括:二維數組,多維數組,廣義表,樹結構,圖結構
非線性結構可以繼續分:集合、樹形結構、圖狀結構
- 集合結構:除了同屬於一種類型外,別無其它關系。
- 樹形結構:元素之間存在一對多關系。常見類型有:樹(有許多特例:二叉樹、平衡二叉樹、查找樹等)
- 圖形結構:元素之間存在多對多關系,圖形結構中每個結點的前驅結點數和后續結點多個數可以任意。
存儲結構表示數據在計算機中的表現形式:
- 順序存儲結構:順序存儲結構將數據存儲在地址連續的存儲單元里。
- 鏈接存儲結構:鏈式存儲結構將數據存儲在任意的存儲單元里,通過保存地址的方式找到相關聯的數據元素。
- 索引存儲結構;在存儲數據的同時,簡歷數據的索引數據,方便對數據進行查詢;
- 散列存儲結構:通過散列函數對關鍵字進行計算算出元素的存儲地址
2.2、算法介紹
算法(Algorithm)是指解題方案的准確而完整的描述,是一系列解決問題的清晰指令,算法代表着用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。如果一個算法有缺陷,或不適合於某個問題,執行這個算法將不會解決這個問題。不同的算法可能用不同的時間、空間或效率來完成同樣的任務。一個算法的優劣可以用空間復雜度與時間復雜度來衡量。----算法百度百科
算法是計算機處理信息的本質,因為計算機程序本質上是一個算法來告訴計算機確切的步驟來執行一個指定的任務。一般地,當算法在處理信息時,會從輸入設備或數據的存儲地址讀取數據,把結果寫入輸出設備或某個存儲地址供以后再調用。算法是獨立存在的一種解決問題的方法和思想。
其實算法就是解決問題的一種方法或者是思路,所以每個算法都有自己的應用場景,所以很多情況要根據實際情況選擇合適的算法或者是設計算法。所以明白算法的原理,至少能夠讓你在面對不同的場景的時候能夠正確的選擇哪一種算法,提高效率,節約資源,這都是時間和白花花的銀子啊,所以好好學習算法很重要。
算法的五大特性:
- 有窮性(Finiteness):算法的有窮性是指算法必須能在執行有限個步驟之后終止;
- 確切性(Definiteness):算法的每一步驟必須有確切的定義;
- 輸入項(Input):一個算法有0個或多個輸入,以刻畫運算對象的初始情況,所謂0個輸入是指算法本身定出了初始條件;
- 輸出項(Output):一個算法有一個或多個輸出,以反映對輸入數據加工后的結果。沒有輸出的算法是毫無意義的;
- 可行性(Effectiveness):算法中執行的任何計算步驟都是可以被分解為基本的可執行的操作步驟,即每個計算步驟都可以在有限時間內完成(也稱之為有效性)
時間復雜度:
算法的時間復雜度是指執行算法所需要的計算工作量。一般來說,計算機算法是問題規模n 的函數f(n),算法的時間復雜度也因此記做。T(n)=Ο(f(n)),因此,問題的規模n 越大,算法執行的時間的增長率與f(n) 的增長率正相關,稱作漸進時間復雜度(Asymptotic Time Complexity)。
- 時間頻度 一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
- 時間復雜度 在剛才提到的時間頻度中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什么規律。為此,我們引入時間復雜度概念。 一般情況下,算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函數。記作T(n)=O(f(n)),稱O(f(n)) 為算法的漸進時間復雜度,簡稱時間復雜度。
- 在各種不同算法中,若算法中語句執行次數為一個常數,則時間復雜度為O(1),另外,在時間頻度不相同時,時間復雜度有可能相同,如T(n)=n^2+3n+4與T(n)=4n^2+2n+1它們的頻度不同,但時間復雜度相同,都為O(n^2)。 按數量級遞增排列,常見的時間復雜度有:常數階O(1),對數階O(log2n),線性階O(n), 線性對數階O(nlog2n),平方階O(n^2),立方階O(n^3),..., k次方階O(n^k),指數階O(2^n)。隨着問題規模n的不斷增大,上述時間復雜度不斷增大,算法的執行效率越低。
常見的時間復雜度:
執行次數函數舉例 | 階 | 非正式術語 |
12 | O(1) | 常數階 |
2n+3 | O(n) | 線性階 |
3n^2+2n+1 | O(n^2) | 平方階 |
5log2n+20 | O(logn) | 對數階 |
2n+3nlog2n+19 | O(nlogn) | nlogn階 |
6n^3+2n^2+3n+4 | O(n^3) | 立方階 |
2^n | O(2^n) | 指數階 |
常見時間復雜度之間的關系,所消耗的時間從小到達:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
空間復雜度:
算法的空間復雜度是指算法需要消耗的內存空間。其計算和表示方法與時間復雜度類似,一般都用復雜度的漸近性來表示。同時間復雜度相比,空間復雜度的分析要簡單得多.
算法的空間復雜度(Space Complexity)S(n)定義為該算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間復雜度也常常簡稱為空間復雜度。記為S(n)=O(f(n))
空間復雜度(Space Complexity)是對一個算法在運行過程中臨時占用存儲空間大小的量度。一個算法在計算機存儲器上所占用的存儲空間,包括存儲算法本身所占用的存儲空間,算法的輸入輸出數據所占用的存儲空間和算法在運行過程中臨時占用的存儲空間這三個方面。算法的輸入輸出數據所占用的存儲空間是由要解決的問題決定的,是通過參數表由調用函數傳遞而來的,它不隨本算法的不同而改變。存儲算法本身所占用的存儲空間與算法書寫的長短成正比,要壓縮這方面的存儲空間,就必須編寫出較短的算法。算法在運行過程中臨時占用的存儲空間隨算法的不同而異,有的算法只需要占用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種算法是“就地\"進行的,是節省存儲的算法,有的算法需要占用的臨時工作單元數與解決問題的規模n有關,它隨着n的增大而增大,當n較大時,將占用較多的存儲單元。
當然評價算法的好壞不僅僅是算法的時間復雜度和空間復雜度,比如還有正確性,可讀性,鍵值性等,明白了時間復雜度和空間復雜度,就知道什么情況下什么場景可以考慮時間換空間,或者空間換時間了,這些都是根據實際情況而定的,沒有最好的算法,只有更適合的某些場景的算法。
算法中常用的分析方法:遞推法、遞歸法、窮舉法、貪心算法、分治法、動態規划法、迭代法、分支界限法、回溯法。
算法的分類:
算法可大致分為基本算法、數據結構的算法、數論與代數算法、計算幾何的算法、圖論的算法、動態規划以及數值分析、加密算法、排序算法、檢索算法、隨機化算法、並行算法,厄米變形模型,隨機森林算法。算法可以宏泛的分為三類:
- 有限的,確定性算法 這類算法在有限的一段時間內終止。他們可能要花很長時間來執行指定的任務,但仍將在一定的時間內終止。這類算法得出的結果常取決於輸入值。
- 有限的,非確定算法 這類算法在有限的時間內終止。然而,對於一個(或一些)給定的數值,算法的結果並不是唯一的或確定的。
- 無限的算法 是那些由於沒有定義終止定義條件,或定義的條件無法由輸入的數據滿足而不終止運行的算法。通常,無限算法的產生是由於未能確定的定義終止條件 。
三、如何學習數據結構和算法?
- 明確目的,為啥要學習數據結構和算法--提供動力
- 明確方向,明白自己要學習數據結構和算法中的哪些內容
- 動手,動手,動手,懂原理,代碼實現,還有最重要的一步就是總結和分享
- 明白每個數據結構和算法的來歷,特點,優缺點和使用場景
- 可以去看一些java中的源碼,想想別人優秀代碼的實現,為什么要這么寫,還有更優的方案嗎?
- 當然資源也很重要:可以聽課,網上課程很多,看書籍《算法導論》《數學之美》等,網絡資源:算法可視化網站(中文版)
- 可以適度的刷題,這樣可以強化記憶
- 學會提出問題,解決問題,記錄問題,實現解決方案
比如常見的一些數據結構和算法:
- 10 個數據結構:數組、鏈表、棧、隊列、散列表、二叉樹、堆、跳表、圖、Trie 樹;
- 10 個算法:遞歸、排序、二分查找、搜索、哈希算法、貪心算法、分治算法、回溯算法、動態規划、字符串匹配算法
數據結構和算法知識結構思維導圖(引用優秀博文,見參考文章):
參考:
https://www.cnblogs.com/54chensongxia/p/11448695.html
https://www.cnblogs.com/chjxbt/p/10967968.html
https://baike.baidu.com/item/%E7%AE%97%E6%B3%95/209025
https://www.cnblogs.com/songQQ/archive/2009/10/20/1587122.html