數據結構快速盤點 - 非線性結構

2021-02-21 腦洞前端

PS:為了更好的閱讀體驗,推薦閱讀原文,到我的博客中閱讀。

那麼有了線性結構,我們為什麼還需要非線性結構呢? 答案是為了高效地兼顧靜態操作和動態操作。大家可以對照各種數據結構的各種操作的複雜度來直觀感受一下。

樹的應用同樣非常廣泛,小到文件系統,大到網際網路,組織架構等都可以表示為樹結構,而在我們前端眼中比較熟悉的 DOM 樹也是一種樹結構,而 HTML 作為一種 DSL 去描述這種樹結構的具體表現形式。如果你接觸過 AST,那麼 AST 也是一種樹,XML 也是樹結構。。。樹的應用遠比大多數人想像的要得多。

樹其實是一種特殊的圖,是一種無環連通圖,是一種極大無環圖,也是一種極小連通圖。

從另一個角度看,樹是一種遞歸的數據結構。而且樹的不同表示方法,比如不常用的長子 + 兄弟法,對於 你理解樹這種數據結構有著很大用處, 說是一種對樹的本質的更深刻的理解也不為過。

樹的基本算法有前中後序遍歷和層次遍歷,有的同學對前中後這三個分別具體表現的訪問順序比較模糊,其實當初我也是一樣的,後面我學到了一點,你只需要記住:所謂的前中後指的是根節點的位置,其他位置按照先左後右排列即可。比如前序遍歷就是根左右, 中序就是左根右,後序就是左右根, 很簡單吧?

我剛才提到了樹是一種遞歸的數據結構,因此樹的遍歷算法使用遞歸去完成非常簡單,幸運的是樹的算法基本上都要依賴於樹的遍歷。 但是遞歸在計算機中的性能一直都有問題,因此掌握不那麼容易理解的"命令式地迭代"遍歷算法在某些情況下是有用的。如果你使用迭代式方式去遍歷的話,可以藉助上面提到的棧來進行,可以極大減少代碼量。

如果使用棧來簡化運算,由於棧是 FILO 的,因此一定要注意左右子樹的推入順序。

樹的重要性質:

如果樹有 n 個頂點,那麼其就有 n - 1 條邊,這說明了樹的頂點數和邊數是同階的。任何一個節點到根節點存在唯一路徑, 路徑的長度為節點所處的深度

實際使用的樹有可能會更複雜,比如使用在遊戲中的碰撞檢測可能會用到四叉樹或者八叉樹。以及 k 維的樹結構 k-d 樹等。

(圖片來自 https://zh.wikipedia.org/wiki/K-d%E6%A0%91)

二叉樹

二叉樹是節點度數不超過二的樹,是樹的一種特殊子集,有趣的是二叉樹這種被限制的樹結構卻能夠表示和實現所有的樹, 它背後的原理正是長子 + 兄弟法,用鄧老師的話說就是二叉樹是多叉樹的特例,但在有根且有序時,其描述能力卻足以覆蓋後者。

實際上, 在你使用長子 + 兄弟法表示樹的同時,進行 45 度角旋轉即可。

一個典型的二叉樹:

標記為 7 的節點具有兩個子節點, 標記為 2 和 6; 一個父節點,標記為 2,作為根節點, 在頂部,沒有父節點。

(圖片來自 https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/tree/README.zh-CN.md)

對於一般的樹,我們通常會去遍歷,這裡又會有很多變種。

下面我列舉一些二叉樹遍歷的相關算法:

94.binary-tree-inorder-traversal102.binary-tree-level-order-traversal103.binary-tree-zigzag-level-order-traversal144.binary-tree-preorder-traversal145.binary-tree-postorder-traversal199.binary-tree-right-side-view

相關概念:

真二叉樹 (所有節點的度數只能是偶數,即只能為 0 或者 2)

另外我也專門開設了二叉樹的遍歷章節, 具體細節和算法可以去那裡查看。

堆其實是一種優先級隊列,在很多語言都有對應的內置數據結構,很遺憾 javascript 沒有這種原生的數據結構。 不過這對我們理解和運用不會有影響。

堆的特點:

在一個 最小堆(min heap) 中, 如果 P 是 C 的一個父級節點, 那麼 P 的 key(或 value)應小於或等於 C 的對應值. 正因為此,堆頂元素一定是最小的,我們會利用這個特點求最小值或者第 k 小的值。在一個 最大堆(max heap) 中, P 的 key(或 value)大於 C 的對應值。

需要注意的是優先隊列不僅有堆一種,還有更複雜的,但是通常來說,我們會把兩者做等價。

相關算法:

295.find-median-from-data-stream二叉查找樹

二叉排序樹(Binary Sort Tree),又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。

二叉查找樹具有下列性質的二叉樹:

若左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;若右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;

對於一個二叉查找樹,常規操作有插入,查找,刪除,找父節點,求最大值,求最小值。

二叉查找樹,之所以叫查找樹就是因為其非常適合查找,舉個例子, 如下一顆二叉查找樹,我們想找節點值小於且最接近 58 的節點,搜索的流程如圖所示:

(圖片來自 https://www.geeksforgeeks.org/floor-in-binary-search-tree-bst/)

另外我們二叉查找樹有一個性質是: 其中序遍歷的結果是一個有序數組。 有時候我們可以利用到這個性質。

相關題目:

98.validate-binary-search-tree二叉平衡樹

平衡樹是計算機科學中的一類數據結構,為改進的二叉查找樹。一般的二叉查找樹的查詢複雜度取決於目標結點到樹根的距離(即深度),因此當結點的深度普遍較大時,查詢的均攤複雜度會上升。為了實現更高效的查詢,產生了平衡樹。

在這裡,平衡指所有葉子的深度趨於平衡,更廣義的是指在樹上所有可能查找的均攤複雜度偏低。

一些資料庫引擎內部就是用的這種數據結構,其目標也是將查詢的操作降低到 logn(樹的深度),可以簡單理解為樹在數據結構層面構造了二分查找算法。

基本操作:

AVL

是最早被發明的自平衡二叉查找樹。在 AVL 樹中,任一節點對應的兩棵子樹的最大高度差為 1,因此它也被稱為高度平衡樹。查找、插入和刪除在平均和最壞情況下的時間複雜度都是 {\displaystyle O(\log {n})} O(\log{n})。增加和刪除元素的操作則可能需要藉由一次或多次樹旋轉,以實現樹的重新平衡。AVL 樹得名於它的發明者 G. M. Adelson-Velsky 和 Evgenii Landis,他們在 1962 年的論文 An algorithm for the organization of information 中公開了這一數據結構。 節點的平衡因子是它的左子樹的高度減去它的右子樹的高度(有時相反)。帶有平衡因子 1、0 或 -1 的節點被認為是平衡的。帶有平衡因子 -2 或 2 的節點被認為是不平衡的,並需要重新平衡這個樹。平衡因子可以直接存儲在每個節點中,或從可能存儲在節點中的子樹高度計算出來。

紅黑樹

在 1972 年由魯道夫·貝爾發明,被稱為"對稱二叉 B 樹",它現代的名字源於 Leo J. Guibas 和 Robert Sedgewick 於 1978 年寫的一篇論文。紅黑樹的結構複雜,但它的操作有著良好的最壞情況運行時間,並且在實踐中高效:它可以在 {\displaystyle O(\log {n})} O(\log{n})時間內完成查找,插入和刪除,這裡的 n 是樹中元素的數目

字典樹(前綴樹)

又稱 Trie 樹,是一種樹形結構。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜尋引擎系統用於文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。

(圖來自 https://baike.baidu.com/item/%E5%AD%97%E5%85%B8%E6%A0%91/9825209?fr=aladdin) 它有 3 個基本性質:

根節點不包含字符,除根節點外每一個節點都只包含一個字符;從根節點到某一節點,路徑上經過的字符連接起來,為該節點對應的字符串;immutable 與 字典樹

immutableJS的底層就是share + tree. 這樣看的話,其實和字典樹是一致的。

相關算法:

208.implement-trie-prefix-tree圖

前面講的數據結構都可以看成是圖的特例。 前面提到了二叉樹完全可以實現其他樹結構, 其實有向圖也完全可以實現無向圖和混合圖,因此有向圖的研究一直是重點考察對象。

圖論〔Graph Theory〕是數學的一個分支。它以圖為研究對象。圖論中的圖是由若干給定的點及連接兩點的線所構成的圖形,這種圖形通常用來描述某些事物之間的某種特定關係,用點代表事物,用連接兩點的線表示相應兩個事物間具有這種關係。

圖的表示方法

空間複雜度 O(n^2),n 為頂點個數。

優點:

判斷兩個頂點是否連接,獲取入度和出度以及更新度數,時間複雜度都是 O(1)

對於每個點,存儲著一個鍊表,用來指向所有與該點直接相連的點 對於有權圖來說,鍊表中元素值對應著權重

例如在無向無權圖中:

(圖片來自 https://zhuanlan.zhihu.com/p/25498681)

可以看出在無向圖中,鄰接矩陣關於對角線對稱,而鄰接鍊表總有兩條對稱的邊 而在有向無權圖中:

(圖片來自 https://zhuanlan.zhihu.com/p/25498681)

圖的遍歷

圖的遍歷就是要找出圖中所有的點,一般有以下兩種方法:

深度優先遍歷:(Depth First Search, DFS)

深度優先遍歷圖的方法是,從圖中某頂點 v 出發, 不斷訪問鄰居, 鄰居的鄰居直到訪問完畢。

廣度優先搜索:(Breadth First Search, BFS)

廣度優先搜索,可以被形象地描述為 "淺嘗輒止",它也需要一個隊列以保持遍歷過的頂點順序,以便按出隊的順序再去訪問這些頂點的鄰接頂點。


----完-



相關閱讀:數據結構快速盤點 - 線性結構

相關焦點

  • java數據結構系列——什麼是數據結構
    讓我用我的理解來告訴你,什麼是數據結構。概述數據結構是計算機組織、存儲數據的方式。簡單來說就是,數據按指定的規則進行存儲,從而得到一個有固定存儲格式的數據集合,就稱之為「數據結構」。查看數據元素快因為每個存儲單元對應一個序號,每個序號存儲一個數據元素。通過序號可以快速的查找到數據。缺點:插入、刪除數據慢因為每次執行此類操作都需要移動元素。
  • 線性結構和非線性結構,你真的分得清楚嗎?
    今天,給大家複習的理論題知識點是數據結構的兩大類型。數據結構分為兩大類型:線性結構和非線性結構。1、線性結構的條件(一個非空數據結構):(1)有且只有一個根結點;(2)每一個結點最多有一個前件,也最多有一個後件。
  • 盤點數據結構的應用場景
    數據結構是計算機編程中最重要的內容之一,我們經常會看到一個公式,那就是程序=數據結構+算法。從這個公式我們就能夠看出來數據結構是多麼的重要,要想寫出優雅高效的程序,一定離不開良好的數據結構,今天我們就來盤點一下常用的數據結構的應用場景。
  • 前端學習數據結構與算法系列(一):初識數據結構與算法
    什麼是數據結構數據存儲於內存時,決定了數據順序和位置關係的便是「數據結構」數據結構一般分為兩個維度:邏輯結構和存儲結構邏輯結構邏輯結構即數據之間的關係,邏輯結構可以分為兩種:線性結構和非線性結構常用的線性結構有:棧、隊列、鍊表、線性等。非線性結構各個數據元素不再保持在一個線性序列中,每個數據元素可能與零個或者多個其他數據元素發生聯繫。
  • 快速入門數據結構和算法
    本文簡要分享算法基礎、常見的數據結構以及排序算法,給同學們帶來一堂數據結構和算法的基礎課。文末福利:阿里雲開發者訓練營來了。一  前言1  為什麼要學習算法和數據結構?2  業務開發要掌握到程度? 二  數據結構基礎1  什麼是數據結構?數據結構是數據的組織、管理和存儲格式,其使用目的是為了高效的訪問和修改數據。數據結構是算法的基石。如果把算法比喻成美麗靈動的舞者,那麼數據結構就是舞者腳下廣闊而堅實的舞臺。2  物理結構和邏輯結構的區別?
  • 《普門品》記誦次第:非線性與結構式
    為此,小編嘗試把記憶順序打亂記憶,進行跳躍式非線性結構式記憶,感覺比原來的順序線性記誦效果好了很多。跳躍式非線性結構式的記誦方法,一定程度上是對記誦對象進行拆解和重構,能夠加深對記誦內容邏輯結構的理解;跳躍式非線性結構式記誦,能夠充分利用記憶的首因效應和尾因效應,分點突破;跳躍式非線性結構式記誦,根據記憶內容的難度靈活安排,難易交替,可以重點突破,克服一些難點、盲點,防止大腦不專注開溜等。當然,跳躍式非線性結構式記誦,是建立在平時的線性記誦基礎之上。
  • 快速介紹常用數據結構
    來源 | http://suo.im/6oo92L快速介紹8種常用數據結構數據結構是一種特殊的組織和存儲數據的方式
  • 數據結構和算法學習指南
    從整體到細節,自頂向下,從抽象到具體的框架思維是通用的,不只是學習數據結構和算法,學習其他任何知識都是高效的。先說數據結構,然後再說算法。數據結構的存儲方式只有兩種:數組(順序存儲)和鍊表(鏈式存儲)。
  • 新手必知的Python數據結構詳解
    作者 | 七寸法師,Python開發工程師,慕課網精英講師來源 | 慕課網(imooc.com)概述數據結構是組織數據的方式,以便能夠更好的存儲和獲取數據。數據結構定義數據之間的關係和對這些數據的操作方式。
  • 程式設計師面試必知的8個數據結構
    即使您只是想在當前工作中變得更好,學習數據結構也是必不可少的。讓我們從了解基礎開始。什麼是數據結構?簡而言之,數據結構是一個以特定布局存儲數據的容器。這種「布局」使數據結構在某些操作中有效,而在另一些操作中效率低下。您的目標是了解數據結構,以便選擇最適合當前問題的數據結構。為什麼我們需要數據結構?
  • 歷年比例41%的算法與數據結構知識點總結
    2、數據結構◆數據結構分為【邏輯結構】和【存儲結構】。線性結構和非線性結構屬於邏輯結構;順序、鏈式、索引屬於存儲結構(物理結構)。循環隊列屬於【存儲結構】。 ★ 數據的存儲結構又稱為物理結構,是數據的邏輯結構在計算機存儲空間中的存放形式。 ◆一個邏輯結構可以有多種存儲結構,且各種存儲結構影響數據處理的效率。
  • 【Python基礎】盤點 Python 10 大常用數據結構(上篇)
    Python 常用數據結構學習目的這個專題,儘量使用最精簡的文字,藉助典型案例盤點Python常用的數據結構。如果你還處於Python入門階段,通常只需掌握list、tuple、set、dict這類數據結構,做到靈活使用即可。
  • 盤點 Python 10 大常用數據結構(下篇)
    學習目的這個專題,儘量使用最精簡的文字,藉助典型案例盤點Python常用的數據結構。如果你還處於Python入門階段,通常只需掌握list、tuple、set、dict這類數據結構,做到靈活使用即可。學習目標學習數據結構第一階段:掌握它們的基本用法,使用它們解決一些基本問題;學習第二階段:知道何種場景選用哪種最恰當的數據結構,去解決題問題;學習第三階段:了解內置數據結構的背後源碼實現,與《算法和數據結構》這門學問裡的知識聯繫起來
  • 考研計算機 | 數據結構—結構算法
    數據的存儲結構實質上是它的邏輯結構在計算機存儲器中的實現,為了的反映一個數據的邏輯結構,它在存儲器中的映象包括兩方面內容,即數據元素之間的信息和數據元素之間的關係。不同數據結構有其相應的若干運算。數據的運算是在數據的邏輯結構上定義的操作算法,如檢索、插入、刪除、更新和排序等。數據的運算是數據結構的一個重要方面,討論任一種數據結構時都離不開對該結構上的數據運算及其實現算法的討論。
  • 數據分析方法:結構分析法
    編輯導語:我們在日常工作中,經常會收集很多數據,比如周報、月報等等,但是真正要用的時候卻還是重新取數;因為我們只有數據,沒有方法,比如我們可以用結構分析法來讀出數據的含義;本文作者分享了關於數據分析方法中的結構分析法,我們一起來看一下。你是不是覺得,平時做的日、周、月、季、年報沒啥用?
  • 數據分析,結構分析法解析
    答:因為光有數據,沒用配解讀數據的方法! 數字要讀出含義才有價值。結構分析法,就是解讀數據的一種簡單、快捷的方法,也是數據分析師的祖傳手藝,今天我們系統講解一下。人們天生討厭平均數,總覺得用平均數很扯淡,有種:「我和姚明平均身高,有毛用」的感覺。
  • 圖解:數據結構中的各種「樹」,你都心中有數嗎?
    來源 | 後端技術學堂作者 | LemonCoder數據結構這門課程是計算機相關專業的基礎課,數據結構指的是數據在計算機中的存儲、組織方式。我們在學習數據結構時候,會遇到各種各樣的基礎數據結構,比如堆棧、隊列、數組、鍊表、樹...這些基本的數據結構類型有各自的特點,不同數據結構適用於解決不同場景下的問題。
  • 【Python基礎】盤點 Python 10 大常用數據結構(下篇)
    學習目的這個專題,儘量使用最精簡的文字,藉助典型案例盤點Python常用的數據結構。如果你還處於Python入門階段,通常只需掌握list、tuple、set、dict這類數據結構,做到靈活使用即可。學習目標學習數據結構第一階段:掌握它們的基本用法,使用它們解決一些基本問題;學習第二階段:知道何種場景選用哪種最恰當的數據結構,去解決題問題;學習第三階段:了解內置數據結構的背後源碼實現,與《算法和數據結構》這門學問裡的知識聯繫起來
  • 圖解:數據結構中的6種「樹」,你心中有數嗎?
    數據結構這門課程是計算機相關專業的基礎課,數據結構指的是數據在計算機中的存儲、組織方式。我們在學習數據結構時候,會遇到各種各樣的基礎數據結構,比如堆棧、隊列、數組、鍊表、樹...這些基本的數據結構類型有各自的特點,不同數據結構適用於解決不同場景下的問題。
  • 多圖,一文了解 8 種常見的數據結構
    對於他的觀點,我不能再苟同了——所以我開始狂補計算機方面的基礎知識,這其中就包括我相對薄弱的數據結構。百度百科對數據結構的定義是:相互之間存在一種或多種特定關係的數據元素的集合。定義很抽象,需要大聲地朗讀幾遍,才有點感覺。怎麼讓這種感覺來得更強烈,更親切一些呢?我來列舉一下常見的 8 種數據結構,數組、鍊表、棧、隊列、樹、堆、圖、哈希表。