es6 實現二叉樹的中序,先序,後序,以及插入,刪除等操作,以及自平衡樹的插入
阿新 • • 發佈:2018-12-28
//二叉樹 class BinarySearchTree { constructor(){ this。root = null this .Node = class { constructor(key){ this。鍵 =鍵入 此。left = null 這個。right = null } } } 插入(鍵){ 讓節點 = 新本 .Node(鍵) ,如果(!此。根){ 此。root = node } else {this。insertNode(此。根,節點) } } insertNode(節點,newNode){ //如果小於當前節點,插入到節點左側,否則插入右側 如果(節點。關鍵 > newNode。鍵){ 如果(節點。左){ 此。insertNode(節點。左,newNode) } else { 節點。left = newNode } } 否則 { 如果(節點。右){ 此。insertNode(節點。右,newNode) } else {節點。right = newNode } } } //中序遍歷是一種以上行順序訪問BST所有節點的方式,也就是以最小到最大的順序訪問所有節點。中序遍歷應用的一種就是對 樹進行排序inOrderTraverse(回撥){ 函式 inOrderTraverseNode(節點,回撥){ 如果(節點){ inOrderTraverseNode(節點。左,回撥) 回撥(節點。鍵) inOrderTraverseNode(節點。右,回撥) } } inOrderTraverseNode(此。根,回撥) } //先序遍歷是以優於後代節點的順序訪問每個節點的先序遍歷的一種應用是列印一棵樹的結構化文件 preOrderTraverse(callBack){ function preOrderTraverseNode(node,callBack){ if(node ){ 回撥(節點。鍵) preOrderTraverseNode(節點。左,回撥) preOrderTraverseNode(節點。右,回撥) } } preOrderTraverseNode(此。根,回撥) } //後序遍歷則是先訪問節點的後代節點,在訪問節點本身,後序遍歷的一個應用是計算一個目錄和它子目錄中所有檔案所佔空間的大小 postOrderTraverse(callBack){ function postOrderTraverseNode(node回撥){ 如果(節點){ postOrderTraverseNode(節點。左,回撥) postOrderTraverseNode(節點。右,回撥) callBack(節點。鍵) } } postOrderTraverseNode(此。根,回撥) } //搜尋節點樹最小值,其實就是最左的值 min(){ let node = this。根 而(節點。左){ 節點 =節點。左 } 返回節點。key } //搜尋節點數最大值,其實就是最右側的值 max(){ let node = this。根 而(節點。右){ 節點 =節點。對 } 返回節點。關鍵 } //搜尋特定的值 的搜尋(鍵){ 函式 searchNode(鍵,節點){ 如果(鍵<節點。鍵){ 返回 searchNode(金鑰,節點。左) } 否則如果(鍵>節點。鍵){ 返回 searchNode(關鍵節點。右) } else { return node } } 返回 searchNode(鍵,這個。根) } //刪除一個節點 remove(key){ this。root = this。的removeNode(此。根,金鑰) } 的removeNode(節點,關鍵){ 如果(!節點){ 返回NULL } 如果(節點。鍵 >鍵){ 節點。左 = 這個。的removeNode(節點。左,鍵) 返回節點 } 否則如果(節點。鍵 <鍵){ 節點。右 = 此。removeNode(節點,右鍵,鍵) 返回節點 } 其他 { //第一種情況:只有一個葉節點 ,如果(!節點離開!&&節點右){ node = null 返回節點 } //第二張情況:有一個子節點 ,如果(!節點左){ 節點=節點。正確的 返回節點 } 否則如果(!節點。右){ 節點=節點。左 返回節點 } //第三種情況:有兩個子節點 //找到當前節點右側樹的最小值(最左側的值)替代當前節點,並刪除當前節點右側樹的最小值 let aux = node。右 而( AUX。左){ 輔助 =輔助。留下 } 節點。鍵 = 輔助。關鍵 節點。右 = 此。的removeNode(節點。右,輔助,關鍵) 返回節點 } } //自平衡樹(AVL樹) // AVL樹是一種自平衡樹。新增或則移除節點時,AVL樹會嚐嚐自平衡。任意一個節點的左子樹和右子樹高度最多相差1 ,新增或移動節點是,AVL樹會盡可能轉換為完全樹 //在AVL樹中插入或者移除節點和BST完全相同。然而,AVL樹的不同之處在於我們需要檢查它的平衡因子,如果有需要,則將其邏輯用於樹的平衡。 insertAVL(鍵){ 如果(!此。根){ 此。root = new this .Node(key) } else { //頂部也可能因為自平衡而重置 此。root = this。insertNodeAVL(此。根,金鑰) } } insertNodeAVL(node,element){ if(node === null){ node = new this .Node(element) } 否則 { 如果(節點。關鍵 >元素){ 節點。左 = 這個。insertNodeAVL(節點左,元件) 如果(節點。左 ==!空 {) //判定平衡因子 如果(此。heightNode(節點。左) - 此。heightNode(節點。右)> 1){ 如果(元件<節點。左側。鍵){ 節點= 這個。rotationLL(節點) } else { 節點= 這個。rotationLR(節點) } } } } 否則如果(節點。關鍵 <元件){ 節點。右 = 此。insertNodeAVL(節點。右,元件) 如果(節點。右 ==!空 {) 如果(此。heightNode(節點。右) - 此。heightNode(節點。左)> 1){ 如果(元件>節點。右。鍵){ 節點= 這個。rotationRR(節點) } else { 節點= 這個。旋轉RL(節點) } } } } } 返回節點 } //計算平衡因子的高度 //在VAL樹中,需要對每個節點計算右子樹的高度(hr)和左子樹高度(hl)的差值,該值應為0,1,-1如果結果不是這三個值之一,則需要平衡該AVL樹,這就是平衡因子的概念 heightNode(node){ if(node === null){ return - 1 } else { return Math。最大值(本。heightNode(節點。左),此。heightNode(節點。右))+ 1 } } //(節點位置)節點操作 //右 - 右(RR)向左單旋轉 //左 - 左(LL)向右單旋轉 //左 - 右(LR)向右雙旋轉先做一次向左單旋轉,在做一次向右單旋轉 //右 - 左(RL)向左雙旋轉先做一次向右單旋轉,在做一次向左單旋轉 rotationRR(node){ let right = node。右 節點。右 = 右。左 右。left = node return right } rotationLL(node){ let left = node。左 節點。左 = 左。右 左。right =節點 return left } rotationLR(node){ 節點。左 = 這個。rotationRR(節點。左) 返回這個。rotationLL(節點) } rotationRL(節點){ 節點。右 = 此。rotationLL(節點。右) 返回這個。rotationRR(節點) } } 讓tree = new BinarySearchTree() 樹。insertAVL(11) 樹。insertAVL(7) 樹。insertAVL(15) 樹。insertAVL(5) 樹。insertAVL(3) 樹。insertAVL(9) 樹。insertAVL(10) 樹。insertAVL(13) 樹。insertAVL(12) 樹。insertAVL(14) 樹。insertAVL(20) 樹。insertAVL(18) 樹。insertAVL(25) 樹。insertAVL(6) // tree.insertAVL(11) 樹。preOrderTraverse(專案=> 控制檯。日誌(項))