淺談二叉樹

1、樹(Tree)

樹形結構是一種非線性數據結構;樹是以分支關係定義的層次結構。

問題來了,什麼是線性數據結構?什麼是非線性數據結構?
線性結構是一組有序數據元素的集合,好比數組隊列,除了第一個元素和最後一個元素之外,其餘元素都是首尾相連的。
非線性結構中各個數據元素沒有對應的順序,每一個數據元素均可能和零個或多個數據元素髮生關係,典型的非線性結構包括二維數組

生活中比較常見的樹形結構:企業組織層級架構、計算機文件系統、族譜等。javascript

2、二叉樹(Binary Tree)

二叉樹是一種特殊的樹形結構,每一個節點(Node)最多隻能有兩棵子樹(SubTree),子樹有左右之分,順序不能任意顛倒。

那麼二叉樹有何特色呢?
能夠高效的插入、查找和刪除數據。html


3、二叉查找樹(Binary Search Tree)的實現

二叉查找樹(BST)是一種特殊的二叉樹,相對較小的值保存在左子樹中,較大的值保存在右子樹中。

首先定義節點,節點是組成二叉樹的基本單元。(如下代碼均用JavaScript實現)前端

function Node(data, left, right) { this.data = data; // 節點值 this.left = left; // 左子樹(左節點) this.right = right; // 右子樹(右節點) this.show = show; // 顯示當前節點值 } function show() { return this.data; }


其次定義BST類,包含:
1.一個根節點,初始化爲null
2.向BST對象中插入節點的insert方法java

function BST() { this.root = null; this.insert = insert; } function insert(data) { var n = new Node(data, null, null); if (this.root === null) { this.root = n; } else { var current = this.root; var parent; while (true) { parent = current; if (data < parent.data) { current = current.left; if (current === null) { parent.left = n; break; } } else { current = current.right; if (current === null) { parent.right = n; break; } } } } }


遍歷二叉查找樹
所謂遍歷,即按照某種順序訪問樹中每一個節點,使得每一個節點都被訪問一次,且僅被訪問一次。
二叉樹由三個基本單元組成——根節點、左節點和右節點,因此遍歷整個二叉樹,也就能夠看做依次遍歷這三部分。
通常遵循先左後右的原則,因此常見的遍歷方案有前序遍歷(根左右)、中序遍歷(左根右)和後序遍歷(左右根)。

前序遍歷node

function preOrder(node) { if (!(node === null)) { console.log(node.show()); preOrder(node.left); preOrder(node.right); } }

 

中序遍歷算法

function inOrder(node) { if (!(node === null)) { inOrder(node.left); console.log(node.show()); inOrder(node.right); } }

 

後序遍歷數組

function postOrder(node){ if (!(node ===null)) { postOrder(node.left); postOrder(node.right); console.log(node.show()); } }

 

以上實現基於遞歸算法數據結構


下面介紹非遞歸算法架構

非遞歸算法須要用到另一種數據結構——,本篇對棧不進行展開敘述,只貼出簡單的JavaScript實現數據結構和算法

function Stack() { this.dataStore = []; this.top = 0; this.push = push; // 入棧 this.pop = pop; // 出棧 this.peek = peek; // 返回棧頂元素 this.clear = clear; // 清空棧 this.length = length; // 返回棧內元素個數 } function push(element) { this.dataStore[this.top++] = element; } function pop() { return this.dataStore[--this.top]; } function peek() { return this.dataStore[this.top - 1]; } function clear() { this.top = 0; } function length() { return this.top; }

 

前序遍歷非遞歸算法

思路:

1.當前節點爲根節點,根節點不爲空且棧不爲空

2.當前節點不爲空,訪問當前節點,當前節點入棧,訪問當前節點左子樹

3.不然,節點出棧,當前節點指向出棧節點右子樹

function preOrder_Stack(root) { var result = []; var stack = new Stack(); var p = root; while (stack.length() || p !== null) { if (p !== null) { stack.push(p); result.push(p.data); // 在遍歷左子樹以前加入根元素 p = p.left; } else { var node = stack.pop(); p = node.right; } } return result; }

 

中序遍歷非遞歸算法

思路:

1.當前節點爲根節點,根節點不爲空且棧不爲空

2.當前節點不爲空,當前節點入棧,訪問當前節點左子樹

3.不然,節點出棧,訪問出棧節點,當前節點指向出棧節點右子樹

function inOrder_Stack(root) { var result = []; var stack = new Stack(); var p = root; while (stack.length() || p !== null) { if (p !== null) { stack.push(p); p = p.left; } else { var node = stack.pop(); result.push(node.data); // 遍歷完左子樹以後加入根元素 p = node.right; } } return result; }

 

後序遍歷非遞歸算法

思路:

後序遍歷訪問順序爲左右根,能夠換個思路,按照根右左的順序訪問,而後利用數組unshift方法實現結果反轉,這樣就轉化成根右左的遍歷算法

1.當前節點爲根節點,根節點不爲空且棧不爲空

2.當前節點不爲空,訪問當前節點,當前節點入棧,訪問當前節點右子樹

3.不然,節點出棧,當前節點指向出棧節點左子樹

function postOrder_Stack(root) { var result = []; var stack = new Stack(); var p = root; while (stack.length() || p !== null) { if (p !== null) { stack.push(p); result.unshift(p.data); p = p.right; } else { var node = stack.pop(); p = node.left; } } return result; }


4、備註

1.第一次寫文,確定有諸多不足,請多多指教,多多批評!

2.花時間寫這篇文章的時候,才真的體會到其中的不易,向各位前輩致敬!

3.參考書目:

[美]Michael McMillan.數據結構與算法JavaScript描述[M]王羣鋒、杜歡譯.北京:人民郵電出版社,2014

嚴蔚敏、吳偉民.數據結構(C語言版)[M].北京:清華大學出版社,1997

4.參考技術博客:

線性結構和非線性結構 - CSDN博客​blog.csdn.net
 
 
相關文章
相關標籤/搜索