使用javascript實現排序二叉樹(2)
上一篇文章我們構造了基本的一個排序二叉樹的資料結構,但是僅僅是定義了一個insert方法去建立二叉排序樹,今天我們來給我們的資料結構新增一些遍歷的功能。
二叉樹的三種遍歷方式(以根節點為準來定義前、中、後)的介紹及其應用場景:
-
前序遍歷
- 順序:根節點 => 左子樹 => 右子樹
- 應用:可以用來構建檔案的目錄結構,輸出所有目錄並分層
-
中序遍歷
- 順序:左子樹 => 根節點 => 右子樹
- 應用:可以進行排序,輸出的結果是一個遞增的序列
-
後續遍歷
- 順序:左子樹 => 右子樹 => 根節點
- 應用:後續遍歷是先遍歷子樹,最後到根節點,可以實現統計節點數、計算資料夾大小的功能
思考 :
- 遍歷的方法是給誰用的,是否需要暴露出去
- 如果暴露出去,怎樣設計才能讓呼叫者能夠獲取到每一個節點並且進行對應的操作
結論 :
- 肯定是要暴露出去給別人呼叫的
- 給別人呼叫,具體的邏輯是不確定的,所以應該是呼叫者傳入一個函式,我們在遍歷的時候把每一次的節點都傳給這個函式,並且去呼叫這個函式,這樣我們不用管具體函式的邏輯,反正已經把它想要的 節點 給他了,具體怎樣操作我們不用管。
分析完畢之後,依然是上次的程式碼,我們給他新增前序中序和後續遍歷的方法:
function BinaryTree(){
var root = null; //根節點預設為null
//節點型別的建構函式
function Node(key){
this.key = key;
this.left = null;
this.right = null;
}
//插入方法
this.insert = function(key){
var newNode = new Node(key);
if(root === null){
root = newNode;
}else{
insertNode(root,newNode)
}
}
var insertNode = function(node,newNode){
if(newNode.key < node.key){
if(node.left === null){
node.left = newNode;
}else{
insertNode(node.left,newNode)
}
}else{
if(newNode.key > node.key){
if(node.right === null){
node.right = newNode;
}else{
insertNode(node.right,newNode)
}
}
}
}
/*--------------------------------------------------------*/
/*
前序遍歷: 根節點 => 左子樹 => 右子樹
*/
this.preTravel = function(callback){
//和上面插入操作類似,都用一個內部的函式來實現具體的邏輯,因為需要使用root
preTravelNode(root,callback);
}
/*
邏輯:
1. 判斷傳入的節點是否為null,如果為null就直接return
2. 如果不為null,則繼續對該節點下的left和right進行遞迴呼叫
3. 具體的呼叫順序根據為 根節點 => 左子樹 => 右子樹
*/
function preTravelNode(node,callback){
if(node !== null){
callback(node.key);
preTravelNode(node.left,callback);
preTravelNode(node.right,callback);
}
}
//中序遍歷
this.middleTravel = function(callback){
middleTravelNode(root,callback);
}
function middleTravelNode(node,callback){
if(node !== null){
middleTravelNode(node.left,callback);
callback(node.key);
middleTravelNode(node.right,callback);
}
}
//後續遍歷
this.nextTravel = function(callback){
nextTravelNode(root,callback);
}
function nextTravelNode(node,callback){
if(node !== null){
nextTravelNode(node.left,callback);
nextTravelNode(node.right,callback);
callback(node.key);
}
}
}
var nodes = [8,7,3,4,6,5,2,9,12]
var binaryTree = new BinaryTree();
nodes.forEach((item)=>{
binaryTree.insert(item)
})
//測試前序遍歷
binaryTree.beforeTravel((key)=>{
console.log(key) // 8,7,3,2,4,6,5,9,10
})
console.log('--------------------')
//中序遍歷
binaryTree.middleTravel((key)=>{
console.log(key) // 2,3,4,5,6,7,8,9,10
})
console.log('--------------------')
//後續遍歷
binaryTree.nextTravel((key)=>{
console.log(key) // 2,5,6,4,3,7,10,9,8
})
具體的邏輯 :
- 判斷傳入的節點是否為null,如果為null就直接return
- 如果不為null,則繼續對該節點下的left和right進行遞迴呼叫
- 具體的呼叫順序根據前序、中序、後序、的訪問節點順序去修改呼叫的順序
還是放上這個二叉樹的圖,根據圖去對比測試的遍歷結果更直觀:
重點 :
- 怎樣設計遍歷方法,呼叫者傳什麼東西進來,我們要暴露什麼東西出去,這個地方得想明白
下期內容 :
- 實現二叉樹的節點查詢功能
- 實現二叉樹中節點的刪除功能
- 實現一個二叉樹的一個小遊戲
上期內容 :