JS遞歸及二叉搜索樹的移除節點


1遞歸含義:在某時某刻某個條件下調用包含自己的函數

2:注意點:⑴遞歸過程中一定要加限制條件,要不然會陷入死循環:

          死循環eg:

function f(someP){ f(somP); } f(4); //Uncaught RangeError: Maximum call stack size exceeded

          正常調用:

//計算輸入某個正整數,然后一直向下疊加 ,這里僅僅做一個簡單示例,不進行輸入num的判斷
function f(num){ let x; if(num>0){ x =num + f(num-1); return x; } return false; } f(5);

                     ⑵遞歸有個過程,不是一步到位的,這一點尤其重要,因為在學習JS數據結構與算法中的二叉搜索樹的移除代碼會至關重要,不懂遞歸過程的話很容易看不懂移除代碼

function getSum(num){ if(x === 1){ return 1; } return num + getSum(num-1) } getSum(5);

      過程如下:

          ①:getSum(5)調用函數並傳入參數5,執行函數中的num +getSum(num-1) ->5+getSum(5-1)

          ②:getSum(4)調用函數並傳入參數4,執行函數中的num+getSum(num-1) ->4+getSum(4-1)

          ③:getSum(3)調用函數並傳入參數3,執行函數中的num+getSum(num-1) ->3+getSum(3-1)

          ④:getSum(2)調用函數並傳入參數2,執行函數中的num+getSum(num-1) ->2+getSum(2-1)

          ⑤:getSum(1)調用函數並傳入參數1,執行函數中的return 1;

          ⑥:這時候再一步一步往回走,即1+2+3+4+5;即可以理解為遞歸調用過程中,是不會立即計算的,要等到限制條件結束后,才會一步一步往上計算。

3:二叉搜索樹的移除節點:移除節點程序是二叉搜索樹程序方法中最復雜的一個。

   eg:

    

class Node{ //節點類 constructor(key){ this.key = key; this.left = null; this.right = null; } } function defaultCompare(a, b) { //比較函數 if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; } const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 }; class BinarySearchTree{ constructor(compareFn = defaultCompare){ this.compareFn = compareFn; this.root = null; } remove(key){ this.root = this.removeNode(this.root,key); } removeNode(node,key){ if(node == null){ return null; } if(this.compareFn(key,node.key) === Compare.LESS_THAN){ // (1) node.left = this.removeNode(node.left,key); //(2) return node;                            //(3) }else if (this.compareFn(key,node.key) === Compare.BIGGER_THAN){  //(4) node.right = this.removeNode(node.right,key);            //(5) return node;                               //(6)  }else{                                    //(7) if(node.left == null && node.right == null){     //(8)    //第一種情況,移除一個葉節點(只有父節點沒有子節點的節點) node = null;                              //(9) return node;                             //(10) } if(node.left == null){               //第二種情況,移除有一個左or右子節點的節點 node = node.right;                          //(11) return node;                             //(12) }else if(node.right == null) { node = node.left; //(13) return node;                             //(14) } const aux = this.minNode(node.right); //(15) //第三種情況,移除有兩個子節點的節點 node.key = aux.key;                //(16) node.right = this.removeNode(node.right,aux.key); //(17) return node;                      //(18) } } }
const tree1 = new BinarySearchTree();
tree1.remove(8);
 
        

    假設現在有一個節點順序為

   

        現在我們需要移除節點8,則代碼的順序應該是:

①:開始時key:8   node: Node{ key: 11, left : Node, right : Node},進入行(1),判斷大小后進入行(2),此時key:8   node: Node{ key: 7, left : Node, right : Node}

②:遞歸調用第一次,進入行(4)判斷大小后進入行(5),此時key:8   node: Node{ key: 9, left : Node, right : Node}

③:遞歸調用第二次,進入行(1)判斷大小后進入行(2),此時key:8   node: Node{ key: 8, left : null, right : null}

④:遞歸調用第三次,進入行(7 ,8, 9),返回一個node,此時key: 8 ,node :null;

⑤:進入行(3),此時結果為: key:8 ,node:Node{key: 9 ,left:null,right:Node};

⑥:進入行(6),此時結果為: key:8 ,node:Node{key: 9 ,left:Node,right:Node};

⑦:進入行(3),此時結果為:key:8 ,node:Node{key: 11,left:Node,right:Node};

⑧:返回到remove()后,跳出程序,節點8已移除。

   備注1:上述步驟只實現了第一種情況,如果有需要,讀者可以用chrome的調試工具進行斷點調試,在Sources中可查看key及node的具體情況,

      備注2:這里很明顯說明了遞歸調用的執行順序,我就是因為不懂執行順序,這段代碼看了我2個多小時。。。。。切記切記,


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM