樹是一種非順序數據結構,對於存儲須要快速查找的數據很是有用。樹是一種分層數據的抽象模型,現實生活中最多見的例子就是家譜,或者是公司的組織架構圖。node
樹中的每個元素都是節點,節點分爲內部節點和外部節點。其中:
至少有一個子節點的節點稱爲內部節點(例如圖中節點7,5,9,15,13,20),沒有子元素的節點爲外部節點或葉節點(例如圖中節點3,6,8,10,12,14,18,25)。
位於樹頂部的節點叫作根節點,它沒有父節點。
節點的一個屬性是深度,節點的深度 取決於它的祖先節點的數量。樹的高度取決於深度的最大值。一樣一棵樹也能夠分爲層級,根節點在第0層,它的子節點在第1層,以此類推。數據結構
二叉樹的節點最多隻能有兩個節點,而二叉搜索樹只容許在左側的節點處存儲(比父節點)小的值,在右側節點存儲(比父節點)大的值。架構
const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 }; function defaultCompare(a, b) { if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; }; class Node { constructor(key) { this.key = key; this.left = undefined; this.right = undefined; }; //下面咱們會聲明BinarySearchTree類的基本骨架 class BinarySearchTree { constructor(compareFn = defaultCompare) { this.compareFn = compareFn; this.root = undefined; }
insert(key) { // special case: first key if (this.root == null) { this.root = new Node(key); } else { this.insertNode(this.root, key); } } insertNode(node, key) { if (this.compareFn(key, node.key) === Compare.LESS_THAN) { if (node.left == null) { node.left = new Node(key); } else { this.insertNode(node.left, key); } } else if (node.right == null) { node.right = new Node(key); } else { this.insertNode(node.right, key); } }
中序遍歷是一種以上行順序訪問BST全部節點的遍歷方式,也就是從最小到最大的順序訪問全部節點。中序遍歷的一種應用是對樹進行排序操做。函數
//inOrderTraverse接收回調函數做爲參數 inOrderTraverse(callback) { this.inOrderTraverseNode(this.root, callback); } inOrderTraverseNode(node, callback) { if (node != null) { this.inOrderTraverseNode(node.left, callback); callback(node.key); this.inOrderTraverseNode(node.right, callback); } }
先序遍歷是以優先於後代節點的順序訪問沒和節點的。先序遍歷的一種應用是打印一個結構化的文檔、咱們來看代碼實現post
preOrderTraverse(callback) { this.preOrderTraverseNode(this.root, callback); } preOrderTraverseNode(node, callback) { if (node != null) { callback(node.key); this.preOrderTraverseNode(node.left, callback); this.preOrderTraverseNode(node.right, callback); } }
後序遍歷就是縣訪問節點的後代節點,在訪問節點自己。後序遍歷的一種應用是計算一個目錄及其子目錄中全部文件所佔空間的大小this
postOrderTraverse(callback) { this.postOrderTraverseNode(this.root, callback); } postOrderTraverseNode(node, callback) { if (node != null) { this.postOrderTraverseNode(node.left, callback); this.postOrderTraverseNode(node.right, callback); callback(node.key); } }
min() { return this.minNode(this.root); } minNode(node) { let current = node; while (current != null && current.left != null) { current = current.left; } return current; }
max() { return this.maxNode(this.root); } maxNode(node) { let current = node; while (current != null && current.right != null) { current = current.right; } return current; }
search(key) { return this.searchNode(this.root, key); } searchNode(node, key) { if (node == null) { return false; } if (this.compareFn(key, node.key) === Compare.LESS_THAN) { return this.searchNode(node.left, key); } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { return this.searchNode(node.right, key); } return true; }
removeNode(node, key) { if (node == null) { return undefined; } if (this.compareFn(key, node.key) === Compare.LESS_THAN) { node.left = this.removeNode(node.left, key); return node; } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { node.right = this.removeNode(node.right, key); return node; } // key is equal to node.item // handle 3 special conditions // 1 - a leaf node // 2 - a node with only 1 child // 3 - a node with 2 children // case 1 移除一個葉節點 if (node.left == null && node.right == null) { node = undefined; return node; } // case 2 移除有一個左側或者右側子節點的節點 if (node.left == null) { node = node.right; return node; } if (node.right == null) { node = node.left; return node; } // case 3 移除有兩個子節點的節點 const aux = this.minNode(node.right); node.key = aux.key; node.right = this.removeNode(node.right, aux.key); return node; } }