1. 程式人生 > 其它 >二叉搜尋樹-map/set的底層容器(C++實現)

二叉搜尋樹-map/set的底層容器(C++實現)

技術標籤:二叉搜尋樹演算法二叉樹

為了聚焦於二叉搜尋樹演算法的實現,沒有采用模板支援不同資料型別,(key, value)均採用 int 數值。

節點定義

    struct Node {
        int key = 0;
        int value = 0;
        Node *left = nullptr;
        Node *right = nullptr;

        Node() : key(0), value(0), left(nullptr), right(nullptr) {}

        Node(int k, int v) : key(k), value(v), left(nullptr), right(nullptr) {}

        Node(Node *rhs) : key(rhs->key), value(rhs->value), left(rhs->left), right(rhs->right) {}

        Node(int k, int v, Node *left, Node *right) : key(k), value(v), left(left), right(right) {}
    };

二叉搜尋樹定義

    class BST {
    public:
        BST() {}

        BST(Node *p, int size) : root(p), count(size) {}

        void insert(int k, int v);

        int *search(int k);

        bool contain(int k);

        // 深度遍歷
        void preOrder();

        void inOrder();

        void postOrder();

        // 廣度遍歷
        void levelOrder();

        // 最大最小值
        int maxinum();

        int mininum();

        void removeMax();

        void removeMin();

        // 刪除任意節點
        void removeNode(int key);

        // floor/ceil
        int *floor(int key);

        int *ceil(int key);

    private:
        Node *floor(Node *p, int key);

        Node *ceil(Node *p, int key);

        Node *removeNode(Node *p, int key);

        Node *maxinum(Node *p);

        Node *mininum(Node *p);

        Node *removeMax(Node *p);

        Node *removeMin(Node *p);

        Node *insert(Node *p, int k, int v);

        int *search(Node *p, int k);

        bool contain(Node *p, int k);

        void preOrder(Node *p);

        void inOrder(Node *p);

        void postOrder(Node *p);

        void levelOrder(Node *p);


        Node *root = nullptr;
        int count = 0;
    };

插入

   void BST::insert(int k, int v) {
        root = insert(root, k, v);
    }

    Node *BST::insert(Node *node, int k, int v) {
        if (node == nullptr) {
            ++count;  // attention
            return new Node(k, v);
        }

        if (k < node->key) {
            node->left = insert(node->left, k, v);
        } else if (k > node->key) {
            node->right = insert(node->right, k, v);
        } else {
            node->value = v;
        }
        return node;
    }

查詢/是否包含

    int *BST::search(int k) {
        return search(root, k);
    }

    int *BST::search(Node *p, int k) {
        if (p == nullptr) {
            return nullptr;
        }

        if (k == p->key) {
            return &(p->value);
        } else if (k < p->key) {
            return search(p->left, k);
        } else {
            return search(p->right, k);
        }
    }

    bool BST::contain(int k) {
        return contain(root, k);
    }

    bool BST::contain(Node *p, int k) {
        if (!p) {
            return false;
        }
        if (k == p->key) {
            return true;
        } else if (k < p->key) {
            return contain(p->left, k);
        } else {
            return contain(p->right, k);
        }
    }

深度遍歷

   void BST::preOrder() {
        preOrder(root);
    }

    void BST::inOrder() {
        inOrder(root);
    }

    void BST::postOrder() {
        postOrder(root);
    }

    void BST::preOrder(Node *p) {
        if (p) {
            std::cout << p->key << "->" << p->value << " ";
            preOrder(p->left);
            preOrder(p->right);
        }
    }

    void BST::inOrder(Node *p) {
        if (p) {
            inOrder(p->left);
            std::cout << p->key << "->" << p->value << " ";
            inOrder(p->right);
        }
    }

    void BST::postOrder(Node *p) {
        if (p) {
            postOrder(p->left);
            postOrder(p->right);
            std::cout << p->key << "->" << p->value << " ";
        }
    }

廣度遍歷

   void BST::levelOrder() {
        levelOrder(root);
    }

    void BST::levelOrder(Node *p) {
        if (!p) {
            return;
        }
        std::queue<Node *> q;
        q.push(p);
        while (!q.empty()) {
            auto node = q.front();
            std::cout << node->key << "->" << node->value << " ";
            q.pop();

            if (node->left) {
                q.push(node->left);
            }
            if (node->right) {
                q.push(node->right);
            }
        }
    }

獲取最大/最小節點

    int BST::maxinum() {
        assert(count > 0);
        Node *node = maxinum(root);
        return node->key;
    }

    int BST::mininum() {
        assert(count > 0);
        Node *node = mininum(root);
        return node->key;
    }

    Node *BST::maxinum(Node *p) {
        auto node = p;
        while (node->right) {
            node = node->right;
        }
        return node;
    }

    Node *BST::mininum(Node *p) {
        auto node = p;
        while (node->left) {
            node = node->left;
        }
        return node;
    }

刪除最大/最小節點

   void BST::removeMax() {
        if (root) {
            root = removeMax(root);
        }
    }

    void BST::removeMin() {
        if (root) {
            root = removeMin(root);
        }

    }

    Node *BST::removeMax(Node *p) {
        // 迭代實現
        if (p->right == nullptr) {
            // 根節點無右子樹
            Node *lnode = p->left;
            delete p;
            return lnode;
        }
        // 迭代到待刪除最小節點
        auto p1 = p;
        auto p2 = p->right;
        while (p2->right) {
            p1 = p2;
            p2 = p2->right;
        }
        p1->right = p2->left;  // 最大節點可能還有左子節點
        delete p2;
        --count;
        return p;
    }

    Node *BST::removeMin(Node *p) {
        // 迭代實現
        if (p->left == nullptr) {
            // 根節點無左子樹
            Node *rnode = p->right;
            delete p;
            return rnode;
        }
        // 迭代到待刪除最小節點
        auto p1 = p;
        auto p2 = p->left;
        while (p2->left) {
            p1 = p2;
            p2 = p2->left;
        }
        p1->left = p2->right;  // 最小節點可能還有右子節點
        delete p2;
        --count;
        return p;
    }

刪除任意節點

  // 刪除任意節點
    void BST::removeNode(int key) {
        if (contain(key)) {
            root = removeNode(root, key);
        }
    }

    Node *BST::removeNode(Node *p, int key) {
        if (key < p->key) {
            p->left = removeNode(p->left, key);
            return p;
        } else if (key > p->key) {
            p->right = removeNode(p->right, key);
            return p;
        } else {
            if (p->left == nullptr) {
                auto res = p->right;
                delete p;
                return res;
            } else if (p->right == nullptr) {
                auto res = p->left;
                delete p;
                return res;
            } else {
                auto minNode = mininum(p->right);
                Node *newNode = new Node(minNode->key, minNode->value);
                newNode->left = p->left;
                newNode->right = removeMin(p->right);
                return newNode;
            }
        }
    }

floor/ceil

    // floor/ceil
    int *BST::floor(int key) {
        if (count == 0 || key < mininum()) {
            return nullptr;
        }
        Node *node = floor(root, key);
        return &(node->key);
    }

    int *BST::ceil(int key) {
        if (count == 0 || key > maxinum()) {
            return nullptr;
        }
        Node *node = ceil(root, key);
        return &(node->key);
    }

    Node *BST::floor(Node *p, int key) {
        if (p == nullptr) {
            // attention 這兒返回空的含義
            return nullptr;
        }
        // 如果p的key值和要尋找的key值相等
        // 則p本身就是key的floor節點
        if (p->key == key) {
            return p;
        }

        // 如果p的key值比要尋找的key值大
        // 則要尋找的key的floor節點一定在p的左子樹中
        if (p->key > key) {
            return floor(p->left, key);
        }

        // 如果p->key < key
        // 則p有可能是key的floor節點, 也有可能不是(存在比p->key大但是小於key的其餘節點)
        // 需要嘗試向p的右子樹尋找一下
        Node *res = floor(p->right, key);
        if (res != nullptr) {
            return res;
        }
        return p;
    }

    Node *BST::ceil(Node *p, int key) {
        if (p == nullptr) {
            // attention 這兒返回空的含義
            return nullptr;
        }
        // 如果p的key值和要尋找的key值相等
        // 則p本身就是key的ceil節點
        if (p->key == key) {
            return p;
        }

        // 如果p的key值比要尋找的key值小
        // 則要尋找的key的ceil節點一定在p的右子樹中
        if (p->key < key) {
            return ceil(p->right, key);
        }

        // 如果p->key > key
        // 則p有可能是key的ceil節點, 也有可能不是(存在比p->key小但是大於key的其餘節點)
        // 需要嘗試向p的左子樹尋找一下
        Node *res = ceil(p->left, key);
        if (res != nullptr) {
            return res;
        }
        return p;
    }

測試

    // 二叉搜尋樹測試
    void BSTTest() {
        BST bstree;
        // 插入
        bstree.insert(5, 50);
        bstree.insert(4, 40);
        bstree.insert(9, 90);
        bstree.insert(1, 10);
        bstree.insert(7, 70);
        bstree.insert(3, 30);
        bstree.insert(6, 60);
        bstree.insert(8, 80);
        bstree.insert(11, 110);
        bstree.insert(10, 100);

        // 深度遍歷遍歷
        bstree.preOrder();
        std::cout << std::endl;
        bstree.inOrder();
        std::cout << std::endl;
        bstree.postOrder();
        std::cout << std::endl;
        // 廣度遍歷
        bstree.levelOrder();
        std::cout << std::endl;

        // 搜尋
        auto sv = bstree.search(10);
        bool cv = bstree.contain(10);
        sv = bstree.search(11);
        cv = bstree.contain(11);
        sv = bstree.search(8);
        cv = bstree.contain(8);
        sv = bstree.search(13);
        cv = bstree.contain(13);

        // 最大最小值
        int minnum = bstree.mininum();
        int maxnum = bstree.maxinum();
//        bstree.removeMin();
//        bstree.levelOrder();
//        std::cout << std::endl;
//        bstree.removeMax();
//        bstree.levelOrder();
//        std::cout << std::endl;

        // 刪除任意節點
//        bstree.removeNode(8);
//        bstree.levelOrder();
//        std::cout << std::endl;
//        bstree.removeNode(1);
//        bstree.levelOrder();
//        std::cout << std::endl;
//        bstree.removeNode(4);
//        bstree.levelOrder();
//        std::cout << std::endl;
//        bstree.removeNode(8);
//        bstree.levelOrder();
//        std::cout << std::endl;
//        bstree.removeNode(9);
//        bstree.levelOrder();
//        std::cout << std::endl;

        // floor/ceil
        auto floorv = bstree.floor(4);
        floorv = bstree.floor(2);
        floorv = bstree.floor(0);
        floorv = bstree.floor(3);

        auto ceilv = bstree.ceil(5);
        ceilv = bstree.ceil(12);
        ceilv = bstree.ceil(2);
        ceilv = bstree.ceil(3);
        ceilv = bstree.ceil(8);

        return;
    }

參考:

https://blog.csdn.net/weixin_42983849/article/details/105622493

https://github.com/liuyubobobo/Play-with-Algorithms/blob/master/05-Binary-Search-Tree/Course%20Code%20(C%2B%2B)/Optional-05-Floor-and-Ceil-in-BST/main.cpp