美文网首页
7-二叉搜索树

7-二叉搜索树

作者: buding_ | 来源:发表于2024-05-05 17:06 被阅读0次

    二叉搜索树(Binary Search Tree)

    是应用非常广泛的一种二叉树,简称BST,又被称为二叉查找树、二叉排序树

    特点如下:
    任意一个节点的值都大于其左子树所有节点的值
    任意一个节点的值都小于其右子树所有节点的值
    它的左右子树也都是一棵二叉搜索树
    二叉搜索树存储的元素必须具备可比较性,不允许为null

    template<class E>
    class BinarySearchTree {
    
    private:
        template<class E1>
        //节点类
        class TreeNode {
        public:
            explicit TreeNode(E ele, TreeNode* par = nullptr):val(ele),parent(par) {
    
            }
            E val;
            TreeNode<E1> *left{nullptr};
            TreeNode<E1> *right{nullptr};
            TreeNode<E1> *parent{nullptr};
    
        };
        //成员信息
        TreeNode<E> *m_root{nullptr};
        int m_size{0};
        std::function<bool (const E&, const E&)> m_comparator;
    
    public:
        //默认构造,调取 e1>e2 即元素需要可比较或者重载>运算符
        BinarySearchTree():m_comparator([](const E& e1, const E& e2) { return e1 > e2; }) {
    
        }
        //传入比较器的构造
        explicit BinarySearchTree(std::function<bool (const E&, const E&)> comp): m_comparator(comp) {
    
        }
    
        ~BinarySearchTree() {
            delete m_root;
        }
        //添加元素
        void add(E ele) {
            if (m_root == nullptr) {
                m_root = new TreeNode<E>(ele);
                m_size++;
    
            } else {
                //1-找到父节点 以及属于左/右节点
                TreeNode<E> *note = m_root;
                int com = 0;
                while (true) {
                    com = compare(ele, note->val);
                    if (com > 0) {
                        TreeNode<E> *right = note->right;
                        if (right == nullptr) {
                            break;
                        } else {
                            note = right;
                        }
                    } else if (com < 0) {
                        TreeNode<E> *left = note->left;
                        if (left == nullptr) {
                            break;
                        } else {
                            note = left;
                        }
                    } else {//相同则不处理
                        return;
                    }
                }
                if (com > 0) {
                    note->right = new TreeNode<E>(ele, note);
                } else {
                    note->left = new TreeNode<E>(ele, note);
                }
                m_size++;
            }
        }
        int size() {
            return m_size;
        }
        bool isEmpty() {
            return m_size == 0;
        }
        int compare(E e1, E e2) {
            if (m_comparator(e1, e2)) {
                return 1;
            } else if (m_comparator(e2, e1)) {
                return -1;
            }
            return 0;
        }
    
    public:
        void toString() {
            innerToString(m_root, "");
        }
    private:
        void innerToString(TreeNode<E> *ele, std::string prefix) {
            if (ele == nullptr) return;
    
            std::cout << prefix << " " << ele->val << std::endl;
            innerToString(ele->left, prefix+"[L]");
            innerToString(ele->right, prefix+"[R]");
        }
    }
    
    
    二叉树的遍历:

    前序遍历:树状结构展示
    中序遍历:二叉搜索树的中序遍历按升序或降序处理节点
    后序遍历:适用一些先子后父的操作
    层序遍历:计算二叉树的高度,判断一棵树是否为完全二叉树

    
    #include <queue>
    //用于遍历时,迭代每个元素
    template<typename E>
    class Visitor {
    public:
        bool stop = false;
        std::function<bool(E)> visit;
    };
    
    template<class E>
    class BinarySearchTree {
        //前序遍历
    public:
        void preorder(Visitor<E> &vi) {
            innerPreorder(m_root, vi);
        }
    private:
        void innerPreorder(TreeNode<E> *ele, Visitor<E> & vi) {
            if (ele == nullptr || vi.stop) return;
    
            vi.stop = vi.visit(ele->val);
            innerPreorder(ele->left, vi);
            innerPreorder(ele->right, vi);
        }
    
        //中序遍历
    public:
        void inorder(Visitor<E> &vi) {
            innerInorder(m_root, vi);
        }
    private:
        void innerInorder(TreeNode<E> *ele, Visitor<E> &vi) {
            if (ele == nullptr || vi.stop) return;
    
            innerInorder(ele->left, vi);
            if (vi.stop) return;
            vi.stop = vi.visit(ele->val);
            innerInorder(ele->right, vi);
        }
    
        //后序遍历
    public:
        void postorder(Visitor<E>& vi) {
            innerPostorder(m_root, vi);
        }
    private:
        void innerPostorder(TreeNode<E> *ele, Visitor<E>& vi) {
            if (ele == nullptr || vi.stop) {
                return;
            }
            innerPostorder(ele->left, vi);
            innerPostorder(ele->right, vi);
            if (vi.stop) return;
            vi.stop = vi.visit(ele->val);
        }
    
        //层序遍历
    public:
        void levelorder(Visitor<E>& vi) {
            innerLevelorder(m_root, vi);
        }
    private:
        void innerLevelorder(TreeNode<E> *ele, Visitor<E>& vi) {
            if (ele == nullptr) {
                return;
            }
            std::queue<TreeNode<E> *> queue;
            queue.push(ele);
            while (!queue.empty()) {
                TreeNode<E> *e = queue.front();
                queue.pop();
                vi.stop = vi.visit(e->val);
                if (vi.stop) {
                    break;
                }
                if (e->left != nullptr) {
                    queue.push(e->left);
                }
                if (e->right != nullptr) {
                    queue.push(e->right);
                }
            }
        }
    };
    
    计算二叉树的高度
        //获取树的高度
    public:
        int height() {
    //        return heightWithRecursion(m_root);
            return heightWithItreation2(m_root);
        }
    private:
        //使用递归的方式
        int heightWithRecursion(TreeNode<E> *ele) {
            if (ele == nullptr) return 0;
            return 1 + max(heightWithRoot(ele->left), heightWithRoot(ele->right));
        }
        //使用迭代的方式1
        int heightWithItreation(TreeNode<E> *ele) {
            if (ele == nullptr) return 0;
            std::queue<TreeNode<E>*> queue;
            queue.push(ele);
            int h = 0;
            int c = 1;
            while (!queue.empty()) {
                int temp_c = c;
                c = 0;
                for (int i = 0; i < temp_c; i++) {
                    TreeNode<E> *e = queue.front();
                    queue.pop();
                    if (e->left != nullptr) {
                        queue.push(e->left);
                        c++;
                    }
                    if (e->right != nullptr) {
                        queue.push(e->right);
                        c++;
                    }
                }
                h++;
            }
            return h;
        }
        //使用迭代的方式2
        int heightWithItreation2(TreeNode<E> *ele) {
            if (ele == nullptr) return 0;
            std::queue<TreeNode<E>*> queue;
            queue.push(ele);
            int h = 0;
            int ls = 1;
            while (!queue.empty()) {
                TreeNode<E> *e = queue.front();
                queue.pop();
                ls--;
                if (e->left != nullptr) {
                    queue.push(e->left);
                }
                if (e->right != nullptr) {
                    queue.push(e->right);
                }
                if (ls == 0) {
                    ls = queue.size();
                    h++;
                }
    
            }
            return h;
        }
    
    判断是否为完全二叉树
        //判断树是否完全二叉树
    public:
        bool isComplete() {
            if (m_root == nullptr) return false;
    
            std::queue<TreeNode<E>*> queue;
            queue.push(m_root);
            bool needLeafage = false;//是否必须为叶子节点
            while (!queue.empty()) {
                TreeNode<E> *e = queue.front();
                queue.pop();
    
                if (needLeafage) {
                  if (e->left != nullptr || e->right != nullptr) {
                    return false;
                  }
                }
    
                if (e->left != nullptr && e->right != nullptr) {
                    queue.push(e->left);
                    queue.push(e->right);
    
                } else if (e->left == nullptr && e->right != nullptr) {
                    return false;//
    
                } else if (e->left == nullptr && e->right == nullptr) {
                    needLeafage = true;//标记后续都需为叶子
    
                } else if (e->left != nullptr && e->right == nullptr) {
                    needLeafage = true;//标记后续都需为叶子
                    queue.push(e->left);
                }
            }
            return true;
        }
    
    根据遍历结构重构二叉树

    前序遍历+中序遍历
    后序遍历+中序遍历
    ——>可保证重构出唯一的一棵二叉树

    前序遍历+后序遍历
    若它是一棵真二叉树,结果唯一
    否则结果不唯一

    前驱节点

    中序遍历时的前一个节点
    如果是二叉搜索树,前驱节点就是前一个比它小的节点

        TreeNode<E>* predecessor(TreeNode<E> *ele) {
    
            if (ele->left == nullptr) {
                //左节点为空,则顺着父节点找,当找到属于父节点的右子树下时,此时的父节点则为前驱节点
                TreeNode<E> *p = ele->parent;
                if (p == nullptr) return p;
                while (p->parent != nullptr && p == p->parent->left) {
                    p = p->parent;
                }
                return p->parent;
    
            } else {
                //左节点不为空情况下,找左子树的最右边那个节点
                TreeNode<E> *l = ele->left;
                while (l->right != nullptr) {
                    l = l->right;
                }
                return l;
            }
        }
    
    后继节点

    中序遍历时的后一个节点

        TreeNode<E>* successor(TreeNode<E> *ele) {
            if (ele->right != nullptr) {
                TreeNode<E>* r = ele->right;
                while (r->left != nullptr) {
                    r = r->left;
                }
                return r;
    
            } else {
                TreeNode<E>* p = ele->parent;
                if (p == nullptr) return p;
                while (p->parent != nullptr && p == p->parent->right) {
                    p = p->parent;
                }
                return p->parent;
            }
        }
    
    删除指定节点
        TreeNode<E>* node(E ele) {
            auto n = m_root;
            while (n != nullptr) {
                int cmp = compare(n->val, ele);
                if (cmp == 0) {
                    return n;
                } else if (cmp > 0) {
                    n = n->left;
                } else {
                    n = n->right;
                }
            }
            return nullptr;
        }
    
        void remove(E ele) {
            //如果节点度为2,覆盖节点的值为前驱/后继节点, 删除该前驱/后继节点
            //如果节点度为1,让节点的子节点 成为其父节点下的节点
            //如果节点度为0,直接删除该节点
            auto n = node(ele);
            if (n == nullptr) return;
    
            m_size--;
            if (n->hasTwo()) {
                auto pre = predecessor(n);
                n->val = pre->val;
                if (pre->parent && pre == pre->parent->left) {
                    pre->parent->left = nullptr;
                } else if (pre->parent && pre == pre->parent->right) {
                    pre->parent->right = nullptr;
                }
                pre->parent = nullptr;
    
            } else if (n->isLeaf()) {
    
                if (n->parent == nullptr) {//根节点
                    m_root = nullptr;
                    return;
                }
                if (n->parent && n == n->parent->left) {
                    n->parent->left = nullptr;
                } else { // (n->parent && n == n->parent->right)
                    n->parent->right = nullptr;
                }
                n->parent = nullptr;
    
            } else {
                auto next = n->left != nullptr ? n->left : n->right;
                next->parent = n->parent;
    
                if (n->parent == nullptr) {//根节点
                    m_root = next;
                } else {
                    if (n == n->parent->left) {
                        n->parent->left = next;
                    } else {//if (n->parent && n == n->parent->right)
                        n->parent->right = next;
                    }
                    n->parent = nullptr;
                }
    
            }
        }
    

    相关文章

      网友评论

          本文标题:7-二叉搜索树

          本文链接:https://www.haomeiwen.com/subject/nubdxjtx.html