• 面向对象的二叉树的实现


    最近在重新实现各种树的数据结构(BST、AVL等等),其中最基本的就是二叉树的实现。

    Github Repo:https://github.com/sinkinben/DataStructure.git

    本次的实现包括:

    • 根据序列化字符串建树
    • 非递归三序遍历
    • 在终端图形化显示

    建树

    节点定义:

    template <typename T>
    class TreeNode
    {
    private:
        // (x, y) is used to draw the binary tree in the console
        // which is the node's coordinate on the screen
        int x, y;
    
    public:
        T val;
        TreeNode<T> *left, *right, *parent;
        // 'color' variable is due to the implementation of the red and black tree.
        RBColor color;
        // 'factor variable is due to the implementation of the AVLTree.
        AVLFactor factor;
    
    public:
        TreeNode() { left = right = parent = this; }
        TreeNode(T _val)
        {
            val = _val;
            left = right = parent = nullptr;
            x = y = -1;
        }
    
        TreeNode(T _val, TreeNode<T> *_parent)
        {
            val = _val;
            parent = _parent;
            left = right = nullptr;
        }
    
        // This construct function is used for RBTree.hpp
        TreeNode(T _val, TreeNode<T> *_parent, TreeNode<T> *_left, TreeNode<T> *_right, RBColor _color)
        {
            val = _val, parent = _parent, left = _left, right = _right;
            color = _color;
        }
    
        // This construct function is uedf for AVLTree.hpp
        TreeNode(T _val, AVLFactor _factor, TreeNode<T> *_parent)
        {
            val = _val, factor = _factor;
            left = right = nullptr;
            parent = _parent;
        }
    
        int getx() { return x; }
        int gety() { return y; }
        void setx(int _x) { x = _x; }
        void sety(int _y) { y = _y; }
    };
    

    请参考文章二叉树的序列化与反序列化 ,其中「反序列化」过程就是建树。

    非递归三序遍历

    See the fucking source code below.

    std::vector<T> inorder()
    {
        std::vector<T> v;
        if (root == nullptr)
            return v;
        std::stack<TreeNode<T> *> s;
        auto p = root;
        while (!s.empty() || p != nullptr)
        {
            if (p != nullptr)
            {
                s.push(p);
                p = p->left;
            }
            else
            {
                p = s.top(), s.pop();
                v.push_back(p->val);
                p = p->right;
            }
        }
        return v;
    }
    
    std::vector<T> preorder()
    {
        std::vector<T> v;
        if (root == nullptr)
            return v;
        std::stack<TreeNode<T> *> s;
        auto p = root;
        s.push(p);
        while (!s.empty())
        {
            p = s.top(), s.pop();
            v.emplace_back(p->val);
            if (p->right != nullptr)
                s.push(p->right);
            if (p->left != nullptr)
                s.push(p->left);
        }
        return v;
    }
    
    std::vector<T> postorder()
    {
        std::vector<T> v;
        if (root == nullptr)
            return v;
        auto p = root;
        std::stack<TreeNode<T> *> s;
        s.push(p);
        while (!s.empty())
        {
            p = s.top(), s.pop();
            v.push_back(p->val);
            if (p->left != nullptr)
                s.push(p->left);
            if (p->right != nullptr)
                s.push(p->right);
        }
        std::reverse(v.begin(), v.end());
        return v;
    }
    

    图形化显示

    定义坐标:左上角为 (0,0) 往右是 X 坐标,往下是 Y 坐标。

    二叉树节点坐标:

    • X 坐标:节点在中序遍历序列中的位置(参考 initX 函数)。
    • Y 坐标:节点所在的二叉树的层次(参考 initY 函数)。

    绘制过程参考 draw 函数。

    完整代码

    #ifndef BINARYTREE_H
    #define BINARYTREE_H
    template <typename T>
    class BinaryTree
    {
    protected:
        const std::string NIL = "null";
        const std::string SEPARATOR = ",";
        TreeNode<T> *root;
    
    private:
        TreeNode<T> *generateNode(const std::string &s, TreeNode<T> *parent)
        {
            return s == NIL ? nullptr : new TreeNode<T>(std::stoi(s), parent);
        }
        TreeNode<T> *innerBuild(const std::vector<std::string> &v)
        {
            if (v.size() == 0)
                return nullptr;
            int idx = 0, len = v.size();
            TreeNode<T> *root = new TreeNode<T>(stoi(v[idx++]));
            assert(root != nullptr);
            std::queue<TreeNode<T> *> q;
            q.push(root);
            while (!q.empty())
            {
                auto node = q.front();
                q.pop();
                if (idx < len)
                    node->left = generateNode(v[idx++], node);
                if (idx < len)
                    node->right = generateNode(v[idx++], node);
                if (node->left != nullptr)
                    q.push(node->left);
                if (node->right != nullptr)
                    q.push(node->right);
            }
            return root;
        }
    
        void destroy(TreeNode<T> *subtree)
        {
            if (subtree == nullptr)
                return;
            std::stack<TreeNode<T> *> result;
            auto p = subtree;
            std::stack<TreeNode<T> *> s;
            s.push(p);
            while (!s.empty())
            {
                p = s.top(), s.pop();
                result.push(p);
                if (p->left != nullptr)
                    s.push(p->left);
                if (p->right != nullptr)
                    s.push(p->right);
            }
            while (!result.empty())
            {
                p = result.top(), result.pop();
                if (p != nullptr)
                    delete p;
            }
        }
    
        void initCoordinate()
        {
            int x = 0;
            initXCoordinate(this->root, x);
            initYCoordinate();
        }
        void initXCoordinate(TreeNode<T> *currentNode, int &x)
        {
            if (currentNode == nullptr)
                return;
            initXCoordinate(currentNode->left, x);
            currentNode->setx(x++);
            initXCoordinate(currentNode->right, x);
        }
        void initYCoordinate()
        {
            if (this->root == nullptr)
                return;
            int level = 1;
            std::queue<TreeNode<T> *> q;
            q.push(root);
            while (!q.empty())
            {
                std::queue<TreeNode<T> *> next;
                while (!q.empty())
                {
                    auto p = q.front();
                    q.pop();
                    p->sety(level);
                    if (p->left != nullptr)
                        next.push(p->left);
                    if (p->right != nullptr)
                        next.push(p->right);
                }
                q = next;
                level++;
            }
        }
    
    public:
        BinaryTree()
        {
            root = nullptr;
        }
    
        ~BinaryTree()
        {
            destroy(this->root);
            root = nullptr;
        }
    
        TreeNode<T> *getRoot() { return this->root; }
    
        // 用于通过序列化字符串创建树,节点值 val 需要使用 int 表示
        void buildTree(std::string str)
        {
            if (str.front() == '[' && str.back() == ']')
                str = str.substr(1, str.length() - 2);
    
            // replace "," with " "
            auto pos = str.find(",");
            while (pos != std::string::npos)
            {
                str.replace(pos, 1, " ");
                pos = str.find(",");
            }
    
            // make str into vector
            std::stringstream ss(str);
            std::string buf;
            std::vector<std::string> result;
            while (ss >> buf)
                result.emplace_back(buf);
    
            this->root = innerBuild(result);
        }
    
        void draw(int widthZoom = 3)
        {
            if (root == nullptr)
                return;
    
            initCoordinate();
    
            auto printChars = [](char c, int n) { for (; n > 0; n--) std::cout << c; };
    
            typedef std::tuple<int, int, char> Tuple;
            std::queue<TreeNode<T> *> q;
            std::string sval;
            int x, y, val;
    
            q.push(root);
            while (!q.empty())
            {
                std::queue<TreeNode<T> *> next;
                std::vector<Tuple> tuples;
                int idx = 0;
                while (!q.empty())
                {
                    auto p = q.front();
                    q.pop();
                    bool l = (p->left != nullptr), r = (p->right != nullptr);
                    x = p->getx() * widthZoom, y = p->gety(), val = p->val, sval = std::to_string(val);
                    printChars(' ', x - idx), std::cout << val;
                    idx = x + sval.length();
                    if (l)
                    {
                        next.push(p->left);
                        int a = widthZoom * p->left->getx();
                        int b = x + sval.length() / 2 - 1;
                        tuples.emplace_back(Tuple(a, b, '_'));
                    }
                    if (l || r)
                    {
                        int a = x + sval.length() / 2;
                        tuples.emplace_back(Tuple(a, a, '|'));
                    }
                    if (r)
                    {
                        next.push(p->right);
                        int a = x + sval.length() / 2 + 1;
                        int b = widthZoom * p->right->getx() + std::to_string(p->right->val).length() - 1;
                        tuples.push_back(Tuple(a, b, '_'));
                    }
                }
                std::cout << '
    ';
                idx = 0;
                if (!tuples.empty())
                {
                    for (auto &t : tuples)
                    {
                        int a = std::get<0>(t), b = std::get<1>(t);
                        char c = std::get<2>(t);
                        for (; idx < a; idx++)
                            std::cout << ' ';
                        printChars(c, b - a + 1);
                        idx = b + 1;
                    }
                }
                std::cout << '
    ';
                q = next;
            }
        }
    
        void destroy()
        {
            this->destroy(this->root);
            this->root = nullptr;
        }
    };
    #endif
    
  • 相关阅读:
    5 float f = 3.4,是否正确
    4 String是基本数据类型吗
    3 访问修饰符public,private,protected以及不写(默认)时的区别
    1 请谈谈面向对象的三大特征?
    接口和抽象类有什么区别
    2 Java中 == 和 equals 和 hashCode 的区别
    java中重载(overload)与重写(override)的区别
    servlet中请求转发(forword)和重定向(redirect)的区别
    团队-项目名称五子棋-团队一阶段互评
    团队-项目名称五子棋-开发环境搭建过程
  • 原文地址:https://www.cnblogs.com/sinkinben/p/13700645.html
Copyright © 2020-2023  润新知