簡體   English   中英

二叉搜索樹 - 刪除 function 不改變原始樹

[英]Binary Search Tree - remove function not changing the original tree

我正在嘗試刪除二叉搜索樹中的根節點。

bst.remove(1) 給出了正確的 output 但它不會改變樹本身。

因此,如果我在調用 bst.remove(1) 后檢查 bst,則 output 是不同的。 為什么會這樣?

如果我運行bst=bst.left||bst.right; ,我得到了正確的 output,這讓我相信我的 function 沒有改變原樹。

remove(key) {
   return this.removeImpl(key, this);
  }

  removeImpl(key, node){  
    
      if (node != null) {
      if (key < node.value) {
        // Key might be in the left subtree.
        node.left = this.removeImpl(key, node.left);
      } else if (key > node.value) {
        node.right = this.removeImpl(key, node.right);
      } else {
        // Node found. 
        // Let's see if it has two children.
        
        
        if (node.left && node.right) {
          // Replace current node with 
          // predecessor data
          
          node.value = this.minimum(node.right);
          node.right = this.removeImpl(node.value, node.right);
        } else {
          // Only 1 child.
          // Let's return the child that's valid.
          
          node = node.left || node.right; //node to be removed becomes it's right or left child
    
        }
      }
    }
    return node;
  }

var bst=new BST(1);
bst.insert(2);
bst.insert(3);
bst.insert(4);

bst.remove(1);

bst.remove(1)給出了正確的 output 但它不會改變樹本身。

這是有意的。 你所說的“樹本身”,實際上是根節點。 您的代碼沒有單獨的 class 形式的樹的概念——樹(僅)由根節點隱含 由於刪除節點不是刪除節點的突變,而是其他引用的突變,並且對該根節點的唯一引用是bst變量,因此您需要對bst進行賦值 在刪除樹的最后一個節點的極端情況下,您會期望bst變為null ,因此再次需要對bst進行分配 由於此bst變量不是某些 class 實例的屬性,因此您需要在主代碼中“自己”管理此分配。

下面是分析這種情況的另一種方法:

removeImpl function依賴調用者返回的節點附加到正確的位置。 您可以在removeImpl進行的每個遞歸調用中看到這種情況……例如:

  node.left = this.removeImpl(key, node.left);
  node.right = this.removeImpl(key, node.right);

所以我們可以說調用者改變了樹。 如果removeImpl本身就是調用者(遞歸調用),那么它自己執行突變,但removeImpl初始調用者(即remove )也會這樣做:

return this.removeImpl(key, this);

在這里,我們看到對返回的節點做某事的責任被級聯到了remove的調用者。 那個調用者應該應用這個原則,那就是你當前的代碼是缺乏的。 我們在這里看到了remove的調用:

bst.remove(1)

但是該調用忽略了返回的節點。 這不是應該調用remove的方式。 它應該這樣調用:

bst = bst.remove(1)

通過該更改,代碼始終使用removeremoveImpl方法返回的節點來捕獲更改。

二級系統

以上內容可能看起來過於冗長。 如果您希望bst.remove(1)完成這項工作而無需為bst分配任何東西,那么您應該考慮使用二類系統而不是當前的一類實現。

然后,您將當前的BST class 重命名為Node ,並創建第二個 class ,它將成為容器 class,並且可以命名為BST 當您將BST重命名為Node時,不要忘記在創建節點的地方也使用該名稱(如在insert方法中, new BST應該成為new Node )。

然后加:

class BST {
    constructor() {
        self.root = null; // Now the root is a property, not a global variable
    }
    insert(key) {
        if (self.root == null) self.root = new Node(key);
        else self.root.insert(key);
    }
    remove(key) {
        if (self.root) {
            // Now we mutate the container instance:
            self.root = self.root.remove(key);
        }
    }
}

var bst = new BST();
for (let value of [1, 2, 3, 4]) bst.insert(value);
bst.remove(1);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM