二叉樹的創建、遍歷、查找、刪除
一、二叉樹的基本概念
一棵非空的二叉樹由根結點及左、右子樹這三個基本部分組成。如下圖:
數字8為根節點,1、4、7、13為葉子節點,8的左邊為左子樹,數值都比根節點8小,右邊為右子樹,數值都比根節點8大。
二、二叉樹的遍歷
前序遍歷:根->左->右(8-3-1-6-4-7-10-14-13);
中序遍歷:左->根->右(1-3-4-6-7-8-10-13-14);
後序遍歷:左->右->根(1-4-7-6-3-13-14-10-8);
典型應用分析:
1) 輸出某個文件夾下所有文件名稱(可以有子文件夾)---用先序遍歷實現:
如果是文件夾,先輸出文件夾名,然後再依次輸出該文件夾下的所有文件
2) 統計某個文件夾的大小(該文件夾下所有文件的大小--用後序遍歷實現:
若要知道某文件夾的大小,必須先知道該文件夾下所有文件的大小,如果有子文件夾,若要知道該子文件夾大小,必須先知道子文件夾所有文件的大小。
3)從小到大輸出數據---中序遍歷實現
三、創建二叉樹的實現(遞歸算法)
//創建二叉樹
var BinaryTree=function(){
var Node=function(key){//初始化節點
this.key=key;
this.left=null;
this.right=null;
}
var rootNode=null;
var insertNode=function(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);
}
}
}
this.insert=function(key){
var newNode=new Node(key);
if(rootNode===null){
rootNode=newNode;
}else{
insertNode(rootNode,newNode);
}
}
}
var nodes=[8,3,10,1,6,14,4,7,13];
var binaryTree=new BinaryTree();
nodes.forEach(function(key){
binaryTree.insert(key);
});
四、三種遍歷的實現
//中序遍歷
var inOrderTraverseNode=function(node,callback){
if(node !==null){
inOrderTraverseNode(node.left,callback);
callback(node.key);
inOrderTraverseNode(node.right,callback);
}
}
this.inOrderTraverse=function(callback){
inOrderTraverseNode(rootNode,callback);
};
//前序遍歷
var preOrderTraverseNode=function(node,callback){
if(node !==null){
callback(node.key);
preOrderTraverseNode(node.left,callback);
preOrderTraverseNode(node.right,callback);
}
}
this.preOrderTraverse=function(callback){
preOrderTraverseNode(rootNode,callback);
};
//後序遍歷
var afterOrderTraverseNode=function(node,callback){
if(node !==null){
afterOrderTraverseNode(node.left,callback);
afterOrderTraverseNode(node.right,callback);
callback(node.key);
}
}
this.afterOrderTraverse=function(callback){
afterOrderTraverseNode(rootNode,callback);
};
//以上代碼放在BinaryTree函數裏面定義
var callback=function(key){
console.log(key);
}
binaryTree.preOrderTraverse(callback);
五、二叉樹節點查找
最小值:由於左節點總是比右節點大,所以只要判斷該節點沒有左節點就是最大值。
最大值:只要判斷該節點沒有右節點就是最大值。
指定值:運用遞歸方法進行比較,小於父節點就走左子樹,大於就走右子樹,直到等於指定值。代碼如下:
var minNode=function(node){
if(node){
while(node && node.left !==null){
node=node.left;
}
return node.key;
}
return null;
}
this.min=function(){
return minNode(rootNode);
}
var maxNode=function(node){
if(node){
while(node && node.right !==null){
node=node.right;
}
return node.key;
}
return null;
}
this.max=function(){
return maxNode(rootNode);
}
var searchNode=function(node,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.search=function(key){
return searchNode(rootNode,key)
}
//以上代碼放在BinaryTree函數裏面定義;
console.log(binaryTree.min())//查找最小值
console.log(binaryTree.search(7)?‘has‘:‘no found 7‘)//查找指定值7
六、刪除節點
1、刪除葉子節點
通過遞歸方法,如果節點沒有左節點和右節點就是葉子節點,通過node =null刪除該節點。
2、刪除只有左子樹或者右子樹的節點,比如刪除節點10,那原先指向10的箭頭就指向14.
3、刪除左子樹右子樹都有的節點,比如節點3。由於左節點一定比父節點和右節點大,所以刪除節點3後,節點4將代替節點3的位置,節點4和連接的箭頭消失。如下圖:
4、代碼實現如下:
var findMinNode=function(node){
if(node){
while(node && node.left !==null){
node=node.left;
}
return node;
}
return null;
}
var removeNode=function(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;
}else if(node.left===null){//刪除左節點沒有的節點
node=node.right;
return node;
}else if(node.right===null){//刪除右節點沒有的節點
node=node.left;
return node;
}
//刪除左右節點都有的節點
var aux=findMinNode(node.right);//查找該節點右子樹最小值
node.key=aux.key;//替換要刪除的節點
//刪除掉要刪除節點的右子樹的最小值,也就是aux;
node.right=removeNode(node.right,aux.key);
return node;
}
}
this.remove=function(key){
rootNode=removeNode(rootNode,key)
}
以上代碼放在BinaryTree這個函數裏面定義。
binaryTree.remove(3);
這裏的代碼實現主要用的是遞歸方法,大家可以在瀏覽器上打斷點執行理解。
二叉樹的創建、遍歷、查找、刪除