數據結構:把數據放入結構裏,通過結構裏最基本的計算方法(增、刪、改、查)操作數據。
是什麼
編程要想寫好程序,就需要學習數據結構;可數據結構是什麼呢,我們以畫畫來舉個例子。
一般人畫畫通常就直接畫 --- 如畫水裏的兩條金魚就直接從某一個部分開始,從外形畫起來了。
一般人的畫法結果經常是,畫到後來比例不對,而且常常畫得不像;而專業人士就是畫什麼像什麼、細節特別突出!!!
專業人士又是如何做到的呢 ???
百思不得其解,先看看梵高的作品吧(素描):
就是那個畫向日葵?的梵高。
問一下才明白,專業人士畫的畫都講究框架。
這是初中美術書上的《美杜莎之伐》,美術書上還有一副設計初稿:
這副畫最高層的構圖設計就是倆個金字塔形狀,《美杜莎之伐》就是靠着倆個三角形的金字塔,畫面保持了平衡。
那麼,您再看看梵高的作品,能不能看出什麼呢 ?
除了畫畫之外,我們學習寫作不也講究結構,像總分總......
專業畫家畫畫,他們會把金魚分解成幾個簡單的幾何圖形 --- 如頭是一個大圓(頭)和兩個小圓(兩個眼睛),身子是一個橢圓,鰭和尾巴是幾個三角形。
對於編程來說,寫一個能夠完成特定功能的程序,就相當於是作一幅畫、一篇文章。
因此,也有兩種方法,
- 一般人編程:直接就用一行行代碼去實現功能,這是低水平的做法,有些時候看上去做得快,實際上Bug多,回頭需要修補;
- 專業人士寫:理解需求之後,抽象出作品需要的基本幾何圖形,而後用算法將這些模塊進行組合,寫出符合需求的程序。
這些基本模塊也像繪畫和文章中作爲輪廓的幾何圖形一樣,需要根據畫面需求平滑過渡,而不是照搬照抄。
這些程序中基本的幾何圖形,就是計算機的數據結構。
基本的幾何圖形有(一系列的點被連成了一種規則的形狀):
- 三角形
- 長方形
- 金字塔形
- 圓形
- 橢圓形
編程也有基礎結構(一系列的數據被組織爲一種抽象的形狀):
- 集合
- 線性表
- 樹
- 圖
數據就等同於點,數據結構就是點中常用的具體關係。
歷史
第一種數據結構是集合,因爲計算機起源於數學,所以數據結構也有數學部分的。
集合,就是我們數學上定義的,也是高中數學裏學過的。
集合在數據結構中一般只是一個輔助,是某個複雜的數據結構的一部分。
集合的特點是元素分類且不重複。
第二種數據結構是線性表,這相當於幾何圖形中的直線,也是最基本的數據結構。
線性表這種抽象的數據結構並非起源於科學計算本身,而是計算機早期的應用——辦公自動化。
我們知道,雖然發明計算機的目的是爲了科學計算,但是TA最早期的商業應用則是在管理和商業方面。
在商業上,報表是一種最常見的數據組織形式,而在管理上,最多見的則是人員或者物資的記錄等等。
TA們都可以被抽象爲線性的數據,然後按照 1、2、3、4、5 的順序排列出來。
比如一所大學所有學生的檔案,就是這樣一個個按照順序排列的,而他們的編號就是學號。
因此,很有必要設計一種抽象的數據結構概括所有這些順序排列和儲存的數據,TA就是線性表。
當然,隨着計算機數據規模的擴張,未必能夠給所有的數據都賦予一個編號順序,結構化地存儲,但是TA們依然遵循一個順序的特徵。
比如一個電商交易的日誌記錄,TA是按照所發生的時間順序,一條條線性地記錄下來,因此,線性表的性質TA們也有。
實現線性表的方法有三種:
- 數組
- 鏈表
- 散列
線性表結構關係是一對一。
第三種數據結構是樹。
計算機科學家們正面臨着一個大問題:在我們真實的世界裏,到底是具體的數值重要,還是數值之間相對的大小更重要,或者說相對的次序更重要?
相對大小:在物理上,水的冰點不到 0 度是無法結冰的;
相對次序:在編程裏,AlphaGo 和別人下棋的時候經常會說,這一步棋可以贏取了多少目,可AlphaGo 卻不走 ?這是因爲計算機只看相對的輸贏,所以才走一步穩妥。
在計算機中,由於經常要做的事情是判斷真假、比較大小、排序、挑選最大值這類的操作,而它們在計算機的世界裏又如此重要,所以相對次序比相對大小更重要;於是計算機科學家們專門設計一種數據結構,這種數據結構被稱爲二叉樹。
二叉樹都有一個根,二叉樹的根就是圖中頂上紅色的那個點。
這是爲了將來把二叉樹一層層擴展,二叉樹的根畫在了最頂端,而不是下面,您把自然界的大樹轉180度就可以了。
從根開始都有分叉,只不過二叉樹爲了簡單起見,只能有兩個分叉,不能更多,這一點和自然界的樹不同。
每一個分叉也有一個自己的根結點,就是圖中藍色的那些點,可以把TA們想象成大樹各級主幹分叉前的部分。
當然,您可能會問,如果遇到一個特殊的問題,需要三個分支怎麼辦?
在數學上,兩個分支和 N 個分支是等價的,或者說 N 個分支的情況可以通過倆個分支來實現。
因此,爲了簡單起見,也爲了更好的通用性,我們只研究二叉樹就可以了。
最後,我們知道一棵樹的樹杈還能再分叉,二叉樹也是如此,任何一個枝杈都可以再分出兩枝,這個過程可以無限持續下去。
二叉樹雖然是一種抽象的東西,在自然界中並不存在,但是它卻濃縮了自然界很多事物的共性,那就是分叉、層層遞進和有序。而針對這些共性,科學家們又總結出一些具有普遍性的算法,能夠回過頭來,應用到各種實際問題中。
樹的結構關係是一對多。
樹主要分成倆類:二叉樹和非二叉樹。
- 二叉樹:二叉樹、堆、AVL樹、紅黑樹、默克爾樹。
- 非二叉樹:B樹、哈夫曼樹、字典樹、線段樹、伸展樹、VEB樹、哈希樹、KD樹、區間樹、B+樹、rang Tree、並查集、SBT樹、斯坦納樹、2-3樹、cover Tree、insider Tree。
第四種數據結構是圖。
圖這種數據結構起源於大數學家歐拉。
這是小學數學書上的一道題,好像是二年級..... (我當初試過,所以印象深刻)
圖論是生活中的一個抽象的概念或者說是工具,圍繞圖,計算機科學家們設計了很多算法,然後把很多實際問題抽象出來,用圖論的算法解決。
關於圖的算法有很多,但最重要的是圖的遍歷算法,也就是如何從一個點出發,通過連接的線訪問圖的各個點。
具體的數學推導,可以看看博文《爬蟲導論|如何下載整個互聯網的網頁》。
圖要是學好了,您可以跨學科研究:社會網絡、數據分析、離散數學、網絡爬蟲、道路規劃、機器人導航......
圖的結構關係是多對多。
圖主要是算法:
- 搜索算法:遍歷樹、BFS、DFS
- 匹配問題:最大流算法、匈牙利
- 最短路徑:動態規劃設計思路、Dijkstra、Bellman-Ford、Floyd、A*、JohnSon、Spfa
- 最小生成樹:切分定理、Kruskal、Prim、Gabow+Spfa、BottleNeck、MstReucePrim、SecondaryMSt、Fredman-Tarjan、Chazelle
- 有向圖算法:拓撲排序、強聯通分量
- 網絡流:Ford Fulkerson框架、Edmonds-Kap 、Dinic、MPM、標籤ISPA、HopcaraftKarp、最大流最小割
- 離散數學:歐拉路徑/迴路、哈密爾頓路徑/迴路
- 關鍵路徑
擴展:圖論專題的《圖的大致介紹》。
線性表、樹、圖是數據結構這門學科的主線:
- 一些計算機科學家求多,他們認爲想要更多的功能,就需要更多的結構,關注的是結構的面值。
比如,鏈表搗鼓了多個版本,如單向鏈表、雙向鏈表、循環鏈表。
引入了 矩陣、字符串、哈希表 等結構。
或者是通過基礎的順序存儲結構和鏈式存儲結構搭積木式組合形成了新的結構。
還有排序和查找、各種算法設計思想(如遞歸)、各個領域的算法(如數論、計算幾何、圖論)、AI算法(如遺傳算法)。
求多,越多越好,想要更多的功能,就需要更多的結構。
- 另一些計算機科學家儉省,他們認爲結構本身是一回事,而人怎麼利用這個結構是另一回事。如果人能夠善加利用,就可以給任何結構創造新的價值。利用少的結構,獲取更多的功能,一個結構到了您的手裏,您能不能給TA增加一點創造性的附加值。
他們給當前的結構設定了一個限制,逼着自己在一個框架之內尋找發揮,專注於給已有的結構開發新用途。
從這種視角來看,線性表、樹、圖都是一個東西,線性表是一種受限制的樹,樹是一種受限制的圖,可以說都是圖。
通過限制線性表,得到了新的邏輯結構:棧、隊列、堆。
儉省,不需要太多,釋放少的潛能,取得多的成就。
區別
數據結構、數據類型,我經常分不清,特別是 C語言裏面需要自己實現的數據結構怎麼到了 Python 就變成了數據類型,他們是啥關係?
比如,我準備蓋棟房子:
- 需要各種已經做好並組合的物件,ta是房子的骨架,ta也是程序中的數據結構。
- 當使用各種不同尺寸和標號的鋼筋,如,按直徑分,鋼絲(直徑3~5mm)、細鋼筋(直徑6~10mm)、粗鋼筋(直徑大於22mm),這些鋼筋即程序中的數據類型,做橫樑也許用10mm的鋼筋,做樓梯也許用22mm的鋼筋,這和程序的 int 與 unsigned int 類似。
其實數據結構還是數據結構,只不過有些高級語言爲了方便編程,把數據結構封裝好了,不用重複造輪子。
資料
數據結構,推薦從《大話數據結構》開始:
- 學的線性表的時候看《漫畫算法:小灰的算法之旅》
- 學到樹、圖的時候看《啊哈算法》
- 學算法的時候,看《編程珠璣》
- 想學好樹的時候,看《高級數據結構》
- 如果想可視化線性表、樹、圖,看一下 dot 語言的資料即可,很簡單的,可以操作文件的編程語言都可以畫出來。
二叉樹可視化[C 操作 dot]:
- dot 語言可視化,具體請見《圖的分類與建模、跨語言可視化》。
- 數據結構可視化:https://visualgo.net/en
- 算法可視化:https://algorithm-visualizer.org/backtracking/hamiltonean-cycles
數據結構往往是和算法一起的,數據結構與算法這門課,難點也就是在算法上。
算法訓練,可以參考另一篇:
這篇文章,是不是有什麼不可告人的密祕呢!!值得一看。