前端你也需要了解的演算法,二叉樹概念及JS實現二叉查詢樹
前述:樹是電腦科學中經常用到的一種資料結構。樹是一種非線性的資料結構,以分層的形式儲存資料。樹被用來儲存具有層級關係的資料結構,比如檔案系統中的檔案;樹還被用來儲存有序列表。
樹的定義
樹是由一組以邊連線的節點組成。公司的組織結構圖就是一個樹的例子。
二叉樹
二叉樹是一種特殊的樹,它的子節點個數不超過兩個。二叉樹具有一些特殊的計算性質,使得在它們之上的一些操作異常高效。
樹可以分為幾個層次,根節點是第0層,它的子節點是第一層,子節點的子節點是第2層,以此類推。
樹中任何一層的節點可以都看做是子樹的根,該子樹包含根節點的子節點,子節點的子節點等。
我們定義樹的層數就是樹的深度。
每個節點都有一個與之相關的值,該值有時候也會被稱為鍵。
正是因為二叉樹每個節點的子節點不允許超過兩個,才能寫出高效的程式方便在樹中插入、查詢和刪除資料。
二叉樹形態
滿二叉樹
定義:除最後一層無任何子節點外,每一層上的所有結點都有兩個子結點二叉樹。 也就是說,如果一個二叉樹的層數為K,且結點總數是(2^k) -1 ,則它就是滿二叉樹。
完全二叉樹
定義:若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。
二叉排序樹
二叉排序樹(Binary Sort Tree),又稱二叉查詢樹(Binary Search Tree),亦稱二叉搜尋樹。
二叉查詢樹是一種特殊的二叉樹,相對較小的值儲存在左節點中,較大的值儲存在右節點中。
這一特性使得查詢的效率很高,對於數值型和非數值型的資料,比如單詞和字串,都是如此。
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
(3)左、右子樹也分別為二叉排序樹;
(4)沒有鍵值相等的節點。
程式碼實現二叉查詢樹的基本功能
// index.js 實現二叉查詢樹的基本功能 function BST(){ // 根節點初始化為空 this.root = null; // 插入節點 this.insert = function(data){ // 建立一個節點儲存資料 var node = new Node(data,null,null); // 下面將節點node插入到樹中 // 如果樹是空的,就將節點設為根節點 if (this.root === null) { this.root = node }else{ //樹不為空 // 判斷插在父節點的左邊還是右邊 // 所以先要儲存一下父節點 var current = this.root; var parent; // 如果要插入的節點鍵值小於父節點鍵值,則插在父節點左邊, // 前提是父節點的左邊為空,否則要將父節點往下移一層, // 然後再做判斷 while(true){ // data小於父節點的鍵值 parent = current; if(data < parent.data){ // 將父節點往左下移(插入左邊) // parent = parent.left; current = current.left; // 如果節點為空,則直接插入 if(current === null){ // !!!此處特別注意,如果就這樣把parent賦值為node,也僅僅只是parent指向node, // 而並沒有加到父元素的左邊!!!根本沒有加到樹中去。所以要先記住父元素,再把當前元素加入進去 parent.left = node; break; } }else{ // 將父節點往右下移(插入右邊) current = current.right; if(current === null){ parent.right = node; break; } } } } } //中序遍歷 (左中右) this.inorder = function(node){ if(node){ this.inorder(node.left); console.log(node.show()); this.inorder(node.right); } } // 先序遍歷 (中左右) this.preorder = function(node){ if(node){ console.log(node.show()); this.preorder(node.left); this.preorder(node.right); } } // 後序遍歷 (左右中) this.postorder = function(node){ if(node){ this.preorder(node.left); this.preorder(node.right); console.log(node.show()); } } } //以下定義一個節點類 function Node(data,left,right){ // 節點的鍵值 this.data = data; // 左節點 this.left = left; // 右節點 this.right = right; // 顯示該節點的鍵值 this.show = function(){ return this.data; } }
程式碼實現二叉查詢樹的查詢功能(最大值、最小值、給定值)
// second.js 實現二叉查詢樹的查詢功能(最大值、最小值、給定值)
// 獲取最小值
BST.prototype.getMin = function() {
var current = this.root;
while(current.left !== null){
current = current.left;
}
return current.data;
};
// 獲取最大值
BST.prototype.getMax = function() {
var current = this.root;
while(current.right !== null){
current = current.right;
}
return current.data;
};
// 獲取指定值
BST.prototype.find = function(data) {
var current = this.root;
while(current !== null){
if (current.data === data) {
return current;
}else if(data < current.data){
current = current.left;
}else{
current = current.right;
}
}
return null;
};
程式碼實現二叉查詢樹的刪除節點功能
// third.js 實現二叉查詢樹的刪除節點功能
BST.prototype.remove = function(data) {
this.root = removeNode(this.root, data);
};
function removeNode(node, data) {
if (node == null) {
return null;
}
if (data == node.data) {
// 沒有子節點的節點
if (node.left == null && node.right == null) {
return null;
}
// 沒有左子節點的節點
if (node.left == null) {
return node.right;
}
// 沒有右子節點的節點
if (node.right == null) {
return node.left;
}
// 有兩個子節點的節點
var tempNode = getSmallset(node.right);
node.data = tempNode.data;
node.right = removeNode(node.right, tempNode.data);
return node;
}else if(data < node.data){
node.left = removeNode(node.left, data);
return node;
}else{
node.right = removeNode(node.right, data);
return node;
}
};