zoukankan      html  css  js  c++  java
  • C++ 命令行窗口打印二叉树(图形)

    写这个程序的目的是学习数据结构的时候方便调试,学习起来也比较直观。

    这个是我测试SplayTree时候的gif

    STEP 1

    新建一个头文件,命名为DrawATree.hh, 将以下内容复制进去

    #ifndef DRAWTREE_HH
    #define DRAWTREE_HH
    
    #include <ostream>
    #include <sstream>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    
    namespace
    {
    #define lChild l_child_  //使用前将 l_child_ 更换为 自己树节点的左孩子的名字
    #define rChild r_child_  //使用前将 r_child_ 更换为 自己树节点的右孩子的名字
    #define data   data_     //使用前将 data_ 更换为 自己树节点的数据的变量名
    #define MAXN (1000)      //这棵树的节点上限
    #define PERID (2)        //打印两个节点的横坐标间隔
    unsigned int SUM;  //统计当前遍历到第几个节点
    
    #ifdef _WIN32
    void clear() {system("cls"); }
    #elif __linux__
    void clear() { system("clear"); }
    #endif
    
    // 将光标移动到 (X,Y)
    std::string AXIS(int X, int Y) {
        std::stringstream ss;
        ss<< "33["<< Y << ";" <<X<<"H";
        return ss.str();
    }
    
    struct DrawNode{
        int x,y,dataSize;
    }axisArray[MAXN];
    
    
    //计算节点数据输出的长度
    template <typename TreePtr>
    int dataSize(TreePtr const& root) {
        std::stringstream ss;
        ss << (root->data);
        return (ss.str()).length();
    }
    
    //中序遍历, 从左往右画节点(不连线)
    //横坐标通过全局变量SUM和上一个节点数据的输出长度算出
    //纵坐标通过递归深度判断
    //PERID 是两个节点间隔长度
    template <typename TreePtr>
    void buildDrawTree (TreePtr const& root, int deep) {
        if(!root) return;  //判断空节点,如果你的节点判空和我不一样,这里也要改, 比如我之前的判断空节点是(root->height_== -1).
    
        if(root->lChild)  buildDrawTree(root->lChild, deep+1);
    
        axisArray[SUM] = (struct DrawNode){axisArray[SUM-1].x+axisArray[SUM-1].dataSize+PERID, deep, dataSize(root)};
        std::cout << AXIS(axisArray[SUM].x, axisArray[SUM].y) << root->data;
        ++SUM;
    
        if(root->rChild)  buildDrawTree(root->rChild, deep+1);
    
    }
    
    template <typename TreePtr>
    void Draw (TreePtr const& t) {  //画树函数
        clear();  //清屏
        SUM = 1;
        int maxy = 0;
    
        buildDrawTree<TreePtr> (t, 2);   //每个结点画出来
    
        //画节点间连线,因为画的节点不会太多,所以就写了n^2的算法,比较好实现
        //每个节点只有一个父节点,所以画出每个节点和自己父节点的连线即可
        for(int i=1; i<SUM; i++) {
            //x,y是子节点的坐标,p是父节点的axisArray数组的下标, px,py是父节点的坐标;
            int x = axisArray[i].x, y = axisArray[i].y, p=0, px=0, py=y-1;
    
            if(y==1) continue; // 根结点没有父节点,跳过
    
            for(int j=1; j<SUM; j++) {  //循环找父节点
                if(i==j) continue;
                if((!p || abs(axisArray[j].x-x) < abs(px-x)) && axisArray[j].y+1 == y)
                    p = j, px = axisArray[j].x;
            }
    
            int s = (2*x+axisArray[i].dataSize)>>1;
            std::cout << AXIS(s,py) << '+';
            if(s<px) 
                for(int i=s+1; i<px; i++) std::cout << AXIS(i,py) << '-';
            else
                for(int i=px+axisArray[p].dataSize;i<s; i++) std::cout << AXIS(i,py) << '-';
            maxy = std::max(maxy, y);
        }
        std::cout << AXIS(1,maxy+1);  //打印完把光标移到最下边.
        // getchar();
    }
    } // namespace
    #endif
    

    STEP 2

    修改头文件DrawATree.hh 第12,13,14,51行代码,如果需要的话. 代码中有注释说明怎么修改.

    STEP 3

    测试你的源代码.

     要保证你的节点数据可以用cout<<输出

    #include "DrawATree.hh"
    #include "YourTree.hh"
    
    int main() {
        YourTreeType t;
        Draw(t.root()); // 这里要传入你的根结点的指针!
    }
    

    实例:

    树的头文件: Tree.hh

    typedef struct TreeNode Node;
    typedef Node* PtrNode;
    
    struct TreeNode{
        char c_;
        PtrNode l_child_, r_child_;
        TreeNode(char c) : c_(c), l_child_(0), r_child_(0) {}
        void Insert(PtrNode p, bool left);
    };
    
    void Node::Insert(PtrNode p, bool left) {
        if(left) l_child_ = p;
        else r_child_ = p;
    }
    

    源代码:

    #include "Tree.hh"
    #include "DrawATree.hh"
    #define left (1)
    #define right (0)
    
    int main() {
        PtrNode root = new TreeNode('a');
        root->Insert(new TreeNode('b'), left);
        root->Insert(new TreeNode('c'), right);
        Draw(root);
        getchar();
    }
    

    效果:

  • 相关阅读:
    钱到用时方恨少(随记)
    Ring0 打印log文件
    Mutation Testing(变异测试)
    GitHub
    常用js收藏
    ASP.NET初学者常用知识
    ASP.NET页面刷新方法总结
    C#中抽象类和接口的区别
    GridView 72般绝技
    55种网页常用小技巧
  • 原文地址:https://www.cnblogs.com/rookiezjz/p/12443241.html
Copyright © 2011-2022 走看看