刷题(5)-二叉查找树(3)

39 篇文章 0 订阅


#ifndef CPP_BINARY_SEARCH_TREE_H
#define CPP_BINARY_SEARCH_TREE_H

#include <iostream>
#include <stack>

template <typename T>
class BinarySearchTree{
private:
    struct Node{
        T val;
        Node *left, *right;
        explicit Node(T &_val, Node *_left = nullptr, Node *_right = nullptr)
            : val(_val), left(_left), right(_right) {}
    };

    Node *root;

private:
    Node *copy(Node* ptr);
    void destory();

public:
    BinarySearchTree();
    BinarySearchTree(const BinarySearchTree &rhs);
    ~BinarySearchTree();

    BinarySearchTree &operator=(const BinarySearchTree &rhs);
    bool operator==(const BinarySearchTree &rhs);

    bool find(const T& val) const;
    void insert(const T& val);
    void delete(const T& val);

    void print_tree(ostream &out = std::cout) const;

};


template <typename T>
BinarySearchTree<T>::BinarySearchTree(): root(nullptr) {}


template<typename T>
BinarySearchTree<T>::BinarySearchTree(const BinarySearchTree<T> &rhs):root(nullptr) {
    root = copy(rhs.root);
}


template <typename T>
typename BinarySearchTree<T>::Node *  // 必须要加typename 告诉编译器 node是一个类, 同时返回类型必须加 模板参数
BinarySearchTree<T>::copy(BinarySearchTree<T>::Node *ptr) {  // 函数参数 可加, 可不加模板参数

    /*
    * 先序遍历ptr, 边遍历边拷贝,为遍历到的每个节点设置 相应拷贝节点的左右儿子
    */
    if (!ptr)
        return ptr;

    std::stack<Node *> stk1, stk2;
    ret = new Node(ptr->val);
    stk1.push(ptr);
    stk2.push(ret);
    while (!stk1.empty()){
        Node *cur = stk1.top();
        stk1.pop();
        Node *copy = stk2.top();
        stk2.pop();
        if (cur->right){
            copy->right = new Node(cur->right->val);
            stk1.push(cur->right);
            stk2.push(copy->right);
        }

        if (cur->left) {
            copy->left = new Node(cur->left->val);
            stk1.push(cur->left);
            stk2.push(copy->left);
        }
    }

    return ret;
}




template <typename T>
BinarySearchTree<T>::~BinarySearchTree(){
    destory();
}

template<typename T>
void BinarySearchTree<T>::destory() {
    // 需要后序遍历
    if (!root)
        return;
    stack<Node*> s1, s2;
    s1.push(root);
    while (!s1.empty()){
        Node *cur = s1.top();
        s1.pop();
        s2.push(cur);
        if (cur->left)
            s1.push(cur->left);
        if (cur->right)
            s2.push(cur->right);
    }

    while (!s2.empty()){
        Node *cur = s2.top();
        s2.pop();
        delete cur;
    }
    root = nullptr;
}

template<typename T>
BinarySearchTree<T> &BinarySearchTree<T>::operator=(const BinarySearchTree &rhs) {
    if ((*this) == rhs)
        return *this;
    destory();
    root = copy(rhs.root);
}

template<typename T>
bool BinarySearchTree<T>::operator==(const BinarySearchTree &rhs) {
    return this->root == rhs.root;
}


template<typename T>
bool BinarySearchTree<T>::find(const T& val) const {
    Node *cur = root;
    while (cur){
        if (val < cur->val)
            cur = cur->left;
        else if (val > cur->val)
            cur = cur->right;
        else
            return true;
    }
    return false;
}

template<typename T>
void BinarySearchTree<T>::insert(const T& val) {
    if (!root){
        root = new Node(val);
        return;
    }

    Node *cur = root;
    while (cur){
        if (val < cur->val){
            if (!cur->left){
                cur->left = new Node(val);
                return;
            }
            cur = cur->left;
        } else if (val > cur->val) {
            if (!cur->right){
                cur->right = new Node(val);
                return;
            }
            cur = cur->right;
        } else {
            return;
        }
    }

}

template<typename T>
void BinarySearchTree<T>::delete(const T &val){
    /*
     * 被删除的节点有3种情况:
     * 1) 没有孩子, 我们只需要直接将父节点中,指向要删除节点的指针置为 null
     * 2) 只有一个孩子, 我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的那个唯一孩子就可以了。
     * 3) 有两个孩子,
     *         我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。
     *         然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),
     *         所以,我们可以应用上面两条规则来删除这个最小节点。比如图中的删除节点 18。
     */
    
    Node *p = root;
    Node *pp = nullptr; // 要删除节点的父亲节点
    while (p && p->val != val){
        pp = p;
        if (val > p->val)
            p = p->right;
        else
            p = p->left;
    }

    if (!p) // 没找到
        return;

    if (p->left && p->right){
        Node *min_p = p->right, *min_pp = p; // 找右子树的最小节点。
        while (min_p->left){
            min_pp = min_p;
            min_p = min_p->left;
        }
        p->val = min_p->val; // 将min_p的数据替换到p中
        p = min_p; //  下面就变成了删除min_p了
        pp = min_pp;
    }

    // 只有一个孩子或者没有孩子的情况
    Node *child = p->left?p->left:p->right;
    if (!pp)
        root = child; // 删除的是根节点
    else if (pp->left == p)
        pp->left = child;
    else
        pp->right = child;
    
    delete p;

}


#endif //CPP_BINARY_SEARCH_TREE_H

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值