二叉搜索树移除——iop用while循环而不是递归实现

Binary search tree removal -- iop implemented with while loop instead of recursion

在此视频 (https://youtu.be/WgdzNyhj6BU) 中展示了字典 ADT 的实现,递归用于查找中序前驱。在 47 分钟左右,演讲者说也可以使用 while 循环。我的问题是 while 循环是否可以与用于递归调用的相同函数签名一起使用?获取iop的方法是rightMostChild:

TreeNode*& rightMostChild(TreeNode*& root)
class Dictionary {
    struct TreeNode {
        TreeNode(const int& key, const std::string& value)
            : key (key), value (value), left (nullptr), right (nullptr) {}
        int key;
        std::string value;        
        TreeNode* left;
        TreeNode* right;        
    }; 
    TreeNode* _root;              
public:
    Dictionary() : _root (nullptr) {}        
    std::string find(const int& key)
    {
        TreeNode* item = _find(_root, key);
        if (item == nullptr)
            return "key not in dictionary";
        else
            return item->value;        
    }        
    void insert(const int& key, const std::string& value)
    {        
        _find(_root, key) = new TreeNode(key, value);
    }    
    void del_item(const int& key)
    {
        remove(_root, key);
    }
    void remove(TreeNode*& root, const int& key)
    {
        if (root != nullptr)
        {
            if (root->key == key)
                doRemoval(root);                
            else if (root->key > key)
                remove(root->left, key);
            else
                remove(root->right, key);               
        }
    }    
    void doRemoval(TreeNode*& root)
    {
        if (root->left && root->right)
            twoChildRemove(root);
        else if (root->left == nullptr && root->right == nullptr)
            noChildRemove(root);
        else
            oneChildRemove(root);
    }    
    void noChildRemove(TreeNode*& root)
    {
        TreeNode* temp = root;
        root = nullptr;
        delete temp;
    }    
    void oneChildRemove(TreeNode*& root)
    {
        TreeNode* temp = root;
        if (root->left) root = root->left;
        else root = root->right;
        delete temp;
    }    
    void twoChildRemove(TreeNode*& root)
    {        
        TreeNode*& iop = rightMostChild(root->left);
        root->key = iop->key;
        root->value = iop->value;
        doRemoval(iop);
    }    
     TreeNode*& rightMostChild(TreeNode*& root)
    {
        if (root->right == nullptr) return root;
        else return rightMostChild(root->right);
    }  
private:       
    TreeNode*& _find(TreeNode*& root, const int& key)
    {
        if (root == nullptr)
            return root;
        if (root->key == key)
            return root;
        else if (root->key > key)
            return _find(root->left, key);
        else
            return _find(root->right, key);
    }            
};

我最初尝试过:

TreeNode*& rightMostChild(TreeNode*& root)
    {
        while (root->right != nullptr)
            root = root->right;
        return root;
    }

但这只是将根重新分配给了 iop。由于无法重新分配引用,我不确定如何沿着树向下走到正确的指针,然后 return 该指针作为引用。是否可以使用此结构编写一个 while 循环来 return 对指针的引用?这不是家庭作业;我只是好奇而已。谢谢!

有几种解决方案。

一种是使用双指针

TreeNode *& rightMostChild(TreeNode*& root) {
    TreeNode **n = &root;
    while ((*n)->right != nullptr)
        n = &(*n)->right;
    return (*n)->right;
}

如果不喜欢双指针,可以用单指针:

TreeNode *& rightMostChild(TreeNode*& root) {
    if (root->right == nullptr)
        return root;
    TreeNode *n = root;
    while (n->right->right != nullptr)
        n = n->right;
    return n->right;
}

第三种可能是编译器识别了原版的尾递归,转为循环