美文网首页
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;
            }

        }
    }

相关文章

  • 数据结构与算法之二叉搜索树(八)

    目录 二叉搜索树概念二叉搜索树的接口设计,包括增,删,改,查平衡二叉搜索树 一 二叉搜索树 二叉搜索树是二叉树的一...

  • Algorithm小白入门 -- 二叉搜索树

    二叉搜索树二叉搜索树 BSTBST 的基本操作计算合法的 BST 1. 二叉搜索树 BST 二叉搜索树(Binar...

  • 二叉搜索树

    二叉搜索树 图解二叉树搜索算法图解:二叉搜索树算法二叉查找树(Binary Search Tree),(又:二叉搜...

  • 23-红黑树

    1.二叉搜索树(BST)继承二叉树(BinaryTree) 2.平衡二叉搜索树(BBST)继承二叉搜索树(BST)...

  • 二叉搜索树(Binary Search Tree)

    1. 定义 二叉搜索树(BST)又叫二叉查找树,二叉排序树。二叉搜索树就是一棵二叉树,但是它又具有搜索树的特征: ...

  • 二叉树基础

    二叉树的分类 完全二叉树与满二叉树 二叉搜索树BST 平衡二叉搜索树BBST因为二叉搜索树有可能退化为链表,降低查...

  • 数据结构 经典算法复习

    二叉搜索树, 平衡二叉树(AVL) 红黑树 B树(平衡多路搜索树) B+树(在B树上改造) 二叉搜索树...

  • Swift 验证二叉搜索树- LeetCode

    题目: 验证二叉搜索树 验证二叉搜索树给定一个二叉树,判断其是否是一个有效的二叉搜索树。 假设一个二叉搜索树具有...

  • 树,二叉树,搜索树

    树,二叉树,搜索树 资料 二叉搜索树 Demo 树的遍历 Demo 题目 ◎ 二叉树的中序遍历 ◎ 二叉树...

  • 【数据结构】红黑树

    1、什么是红黑树? 红黑树是一个要求不那么严格的平衡二叉树搜索树(平衡二叉搜索树/AVL树=平衡二叉树+二叉搜索树...

网友评论

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

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