每當放完小長假,我都會習慣性的反思和覆盤一下本身的技術,尤爲是端午節。爲何我會寫二叉樹的文章呢?其實這涉及到程序員的一個成長性的問題。對於0-3年的前端程序員來講,可能不多有機會涉及到數據結構和算法的工做中,除非去大廠或者作架構相關的工做。可是不少工做2-3年的前端工程師,業務工做已經相對熟悉了,各類技術或多或少也都使用過,那麼在這個階段,對於每一個有追求的程序員,是否是應該突破一下本身的技術瓶頸,去研究一些更深層次的知識呢?沒錯,這個階段咱們最應該瞭解的就是數據結構,算法,設計模式相關的知識,設計模式和算法筆者在以前的文章中已經系統的總結過了,感興趣的能夠學習瞭解一下。前端
接下來筆者就係統的總結一下二叉樹相關的知識,而且經過實際代碼一步步來帶你們實現一個二叉搜索樹。vue
二叉樹(Binary tree)是樹形結構的一個重要類型。許多實際問題抽象出來的數據結構每每是二叉樹形式,即便是通常的樹也能簡單地轉換爲二叉樹,並且二叉樹的存儲結構及其算法都較爲簡單,所以二叉樹顯得特別重要。二叉樹特色是每一個結點最多隻能有兩棵子樹,且有左右之分。 node
在實現以前,咱們須要先分析一下BST(二叉搜索)樹。咱們要想構建一棵實用的樹,咱們須要節點和方法,以下圖所示: git
function BinarySearchTree() {
let Node = function(key) {
this.key = key;
this.left = null;
this.right = null;
}
let root = null;
}
複製代碼
咱們按照上圖的二叉搜索樹的結構組織方式,來實現二叉樹的基本方法。程序員
// 插入
this.insert = function(key) {
let newNode = new Node(key);
if(root === null) {
root = newNode;
}else {
insertNode(root, newNode);
}
}
複製代碼
其中insertNode方法用來判斷在根節點不爲空時的執行邏輯,具體代碼以下:github
function insertNode(node, newNode) {
// 若是新節點值小於當前節點值,則插入左子節點
if(newNode.key < node.key) {
if(node.left === null) {
node.left = newNode;
}else{
insertNode(node.left, newNode);
}
}else {
// 若是新節點值大於當前節點值,則插入右子節點
if(node.right === null) {
node.right = newNode;
}else {
insertNode(node.right, newNode);
}
}
}
複製代碼
以上代碼即實現了BST的插入部分邏輯,具體使用方式以下:算法
let tree = new BinarySearchTree()
tree.insert(19)
tree.insert(10)
tree.insert(20)
複製代碼
以上代碼生成的二叉樹結構以下: 數據庫
樹的遍歷是指訪問樹的每一個節點並對它們進行某種操做的過程。具體分爲中序遍歷,先序遍歷和後序遍歷。接下來我會一一介紹給你們。後端
中序遍歷是一種以從最小到最大的順序訪問全部節點的遍歷方式,具體實現以下:設計模式
this.inOrderTraverse = function(cb) {
inOrderTraverseNode(root, cb)
}
function inOrderTraverseNode(node, cb) {
if(node !== null) {
inOrderTraverseNode(node.left, cb)
cb(node.key)
inOrderTraverseNode(node.right, cb)
}
}
複製代碼
具體遍歷過程以下圖所示:
先序遍歷是以優先於後代節點的順序訪問每個節點。具體實現以下:
this.preOrderTraverse = function(cb) {
preOrderTraverseNode(root, cb)
}
function preOrderTraverseNode(node, cb) {
if(node !== null) {
cb(node.key)
preOrderTraverseNode(node.left, cb)
preOrderTraverseNode(node.right, cb)
}
}
複製代碼
具體遍歷以下圖所示:
後序遍歷是先訪問節點的後代節點,再訪問節點自己。。具體實現以下:
this.postOrderTraverse = function(cb) {
preOrderTraverseNode(root, cb)
}
function postOrderTraverseNode(node, cb) {
if(node !== null) {
postOrderTraverseNode(node.left, cb)
postOrderTraverseNode(node.right, cb)
cb(node.key)
}
}
複製代碼
具體遍歷順序以下圖所示:
咱們通常的搜索會有最值搜索(也就是最大值,最小值,中值)和對特定值的搜索,接下來咱們就來實現它們。
在BST樹中搜索特定的值,具體實現以下:
this.search = function(key) {
return searchNode(root, key)
}
function searchNode(ndoe, key) {
if(node === null) {
return false
}
if(key < node.key) {
return searchNode(node.left, key)
}else if(key > node.key) {
return searchNode(node.right, key)
}else {
return true
}
}
複製代碼
實現邏輯也很簡單,這裏你們能夠研究一下。
由二叉樹的結構特徵咱們能夠發現,二叉樹的最左端就是最小值,二叉樹的最右端就是最大值,因此咱們能夠經過遍從來找到最小值,代碼以下:
this.min = function() {
return minNode(root)
}
function minNode(node) {
if(node) {
while(node && node.left !== null) {
node = node.left;
}
return node.key
}
return null
}
複製代碼
和求最小值同樣,最大值也能夠用相似的方法,代碼以下:
this.max = function() {
return maxNode(root)
}
function maxNode(node) {
if(node) {
while(node && node.right !== null) {
node = node.right;
}
return node.key
}
return null
}
複製代碼
移除BST中的節點相對來講比較複雜,須要考慮不少狀況,具體狀況以下:
瞭解了上述3種狀況以後咱們開始實現刪除節點的邏輯:
this.remove = function(key) {
root = removeNode(root, key)
}
function removeNode(node, key) {
if(node === null) {
return null
}
if(key < node.key) {
node.left = removeNode(node.left, key)
return node
}else if(key > node.key) {
node.right = removeNode(node.right, key)
return node
}else {
// 一個葉節點
if(node.left === null && node.right === null) {
node = null;
return node
}
// 只有一個子節點的節點
if(node.left === null) {
node = node.right;
return node
}else if(node.right === null) {
node = node.left;
return node
}
// 有兩個子節點的節點狀況
let aux = findMinNode(node.right);
node.key = aux.key;
node.right = removeNode(node.right, aux.key);
return node
}
}
function findMinNode(node) {
if(node) {
while(node && node.left !== null) {
node = node.left;
}
return node
}
return null
}
複製代碼
至此,一棵完整的搜索二叉樹就實現了,是否是頗有成就感呢?本文的源碼以上傳至筆者的github,感興趣的朋友能夠感覺一下。
二叉樹通常能夠用來:
其實樹的類型還有不少種,這些不一樣類型的樹在計算機中有很普遍的用途,好比紅黑樹,B樹,自平衡二叉查找樹,空間劃分樹,散列樹,希爾伯特R樹等,若是對這些樹敢興趣的朋友能夠深刻研究一下,畢竟對本身將來的技術視野仍是頗有幫助的。
若是想學習更多前端技能,實戰和學習路線, 歡迎在公衆號《趣談前端》加入咱們的技術羣一塊兒學習討論,共同探索前端的邊界。
二叉樹 - baike.baidu.com/item/二叉樹