前述:樹是計算機科學中經常用到的一種數據結構。樹是一種非線性的數據結構,以分層的形式存儲數據。樹被用來存儲具有層級關係的數據結構,比如文件系統中的文件;樹還被用來存儲有序列表。
樹的定義
樹是由一組以邊連接的節點組成。公司的組織結構圖就是一個樹的例子。
二叉樹
二叉樹是一種特殊的樹,它的子節點個數不超過兩個。二叉樹具有一些特殊的計算性質,使得在它們之上的一些操作異常高效。
樹可以分爲幾個層次,根節點是第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;
}
};