二叉樹是一種重要的數據存儲結構,它體現了一對多的數據存儲方式,一顆二叉樹有一個根節點(root),與衆多分結點組成,每個雙親最多有兩個子樹分爲左子樹和右子樹,結點的分支數稱爲這個結點的度,整個二叉樹的度爲最大的度.度爲0的結點稱爲葉結點.
代碼放在GitHub:二叉查找樹
滿二叉樹與完全二叉樹
- 滿二叉樹每個層級的結點都達到最大
- 完全二叉樹必須從左到右依次排序,造成只能右邊存在缺失(如果左邊缺失勢必造成不是正確的排序)
二叉樹的創建
- 每個結點最多隻有兩個分支left(左子樹)、right(右子樹)
使用JavaScript實現二叉樹的創建
/**
* @name: 二叉樹創建封裝
* @params: null
* @return: undefined
*/
function BinarySearchTree() {
// 根節點
this.root=null;
// 結點包括左子樹和右子樹結點和當前的鍵
this.node=function (key) {
this.key=key;
this.left=null;
this.right=null;
};
}
可以看到非常的簡單,每個結點由相應的key、left(左子樹)、right(右子樹)構成,還有一個root(根節點)
添加插入結點的方法
- 小於雙親的結點在雙親的左邊,大於雙親的在雙親的右邊
- 根節點的左邊爲全部小於結點的樹,右邊全部爲大於跟結點
- 如果沒有root(根節點)則插入結點爲根節點
/**
* @name: 二叉樹插入方法
* @params: 插入的鍵
* @return: undefined
*/
BinarySearchTree.prototype.insert=function (key) {
// 創建新結點
let newNode=new this.node(key);
if(this.root===null){
this.root=newNode;
}else{
this.insertRecurse(this.root,newNode);
}
}
/**
* @name:二叉樹遞歸插入方法
* @params: parent(雙親) node(插入的結點)
* @return: undefined
*/
BinarySearchTree.prototype.insertRecurse=function (parent,node) {
// 小於爲左子樹部分,大於爲右子樹部分
if(node.key<parent.key){
parent.left?this.insertRecurse(parent.left,node):parent.left=node;
}
else{
parent.right?this.insertRecurse(parent.right,node):parent.right=node;
}
}
遍歷操作
二叉樹數據結構常用的遍歷方法主要有4種:
- 前序遍歷
- 中序遍歷
- 後序遍歷
- 層序遍歷
各種遍歷操作可以用根節點的位置進行區分,遍歷順序都是優先遍歷左在遍歷右,所以前序遍歷順序爲雙親(D)->左子樹(L)->右子樹( R),中序遍歷順序爲左子樹(L)->雙親(D)->右子樹( R),後序遍歷順序爲左子樹(L)->右子樹( R)->雙親(D),層序遍歷就是從左到右、從上到下進行遍歷,一般沒做說明.
例:如上圖滿二叉樹,前序遍歷順序爲 A BDE CFG,上圖非完全二叉樹遍歷順序爲A BD CEF
JavaScript實現前序遍歷
假設利用上邊的二叉樹插入方法,生成一顆二叉樹如下:
插入數值
var bst=new BinarySearchTree()
bst.insert(11);
bst.insert(5);
bst.insert(8);
bst.insert(10);
bst.insert(15);
bst.insert(16);
bst.insert(12);
bst.insert(14);
bst.insert(17);
則想要實現的前序遍歷順序應該 11 5 8 10 15 12 14 16 17
實現前序遍歷算法:
/**
* @name:前序遍歷算法
* @params: 接收遍歷結果的回調
* @return: undefined
*/
BinarySearchTree.prototype.prevOrderIterate=function(callback) {
this.prevOrderIterateRecurse(this.root,callback);
};
// 前序遍歷遞歸
BinarySearchTree.prototype.prevOrderIterateRecurse=function (node,callback) {
if(node!==null){
// 返回遍歷值
callback(node.key);
// 繼續遍歷左子樹,再遍歷右子樹(利用棧結構特點)
this.prevOrderIterateRecurse(node.left,callback);
this.prevOrderIterateRecurse(node.right,callback);
}
}
/*調用*/
var res=''
bst.prevOrderIterate(function(e) {
res+=' '+e;
})
console.log(res);
JavaScript實現中序遍歷、後序遍歷
思想同前序遍歷,只需改變遞歸操作中的順序即可
/**
* @name:中序遍歷
* @params: 接收參數的回調 callback: [Function]
* @return: undefined
*/
BinarySearchTree.prototype.midOrderInterate=function (callback) {
this.midOrderInterateRecurse(this.root,callback);
};
// 中序遍歷遞歸
BinarySearchTree.prototype.midOrderInterateRecurse=function (node,callback) {
if(node!==null){
this.midOrderInterateRecurse(node.left,callback);
callback(node.key);
this.midOrderInterateRecurse(node.right,callback);
}
};
/**
* @name:後序遍歷
* @params: 後序遍歷的回調 callback [Function]
* @return: undefined
*/
BinarySearchTree.prototype.aftOrderInterate=function (callback) {
this.aftOrderInterateRecurse(this.root,callback);
};
// 後序遍歷遞歸
BinarySearchTree.prototype.aftOrderInterateRecurse=function (node,callback) {
if(node!==null){
this.midOrderInterateRecurse(node.left,callback);
this.midOrderInterateRecurse(node.right,callback);
callback(node.key);
}
}