Print a binary tree in a pretty way

后端 未结 15 1172
我寻月下人不归
我寻月下人不归 2020-11-28 22:15

Just wondering if I can get some tips on printing a pretty binary tree in the form of:

5
     10
          11
          7
               6
     3
          4         


        
相关标签:
15条回答
  • 2020-11-28 22:41

    Here's yet another C++98 implementation, with tree like output.

    Sample output:

    PHP
    └── is
        ├── minor
        │   └── perpetrated
        │       └── whereas
        │           └── skilled
        │               └── perverted
        │                   └── professionals.
        └── a
            ├── evil
            │   ├── incompetent
            │   │   ├── insidious
            │   │   └── great
            │   └── and
            │       ├── created
            │       │   └── by
            │       │       └── but
            │       └── amateurs
            └── Perl
    

    The code:

    void printTree(Node* root)
    {
            if (root == NULL)
            {
                    return;
            }
    
            cout << root->val << endl;
            printSubtree(root, "");
            cout << endl;
    }
    
    void printSubtree(Node* root, const string& prefix)
    {
            if (root == NULL)
            {
                    return;
            }
    
            bool hasLeft = (root->left != NULL);
            bool hasRight = (root->right != NULL);
    
            if (!hasLeft && !hasRight)
            {
                    return;
            }
    
            cout << prefix;
            cout << ((hasLeft  && hasRight) ? "├── " : "");
            cout << ((!hasLeft && hasRight) ? "└── " : "");
    
            if (hasRight)
            {
                    bool printStrand = (hasLeft && hasRight && (root->right->right != NULL || root->right->left != NULL));
                    string newPrefix = prefix + (printStrand ? "│   " : "    ");
                    cout << root->right->val << endl;
                    printSubtree(root->right, newPrefix);
            }
    
            if (hasLeft)
            {
                    cout << (hasRight ? prefix : "") << "└── " << root->left->val << endl;
                    printSubtree(root->left, prefix + "    ");
            }
    }
    
    0 讨论(0)
  • 2020-11-28 22:41

    Do an in-order traversal, descending to children before moving to siblings. At each level, that is when you descent to a child, increase the indent. After each node you output, print a newline.

    Some psuedocode. Call Print with the root of your tree.

    void PrintNode(int indent, Node* node)
    {
        while (--indent >= 0)
            std::cout << " ";
        std::cout << node->value() << "\n";
    }
    
    void PrintNodeChildren(int indent, Node* node)
    {
        for (int child = 0; child < node->ChildCount(); ++child)
        {
            Node* childNode = node->GetChild(child);
            PrintNode(indent, childNode);
            PrintNodeChildren(indent + 1, childNode);
        }
    }
    
    void Print(Node* root)
    {
       int indent = 0;
       PrintNode(indent, root);
       PrintNodeChildren(indent + 1, root);  
    }
    
    0 讨论(0)
  • 2020-11-28 22:45

    i have a easier code.......... consider a tree made of nodes of structure

     struct treeNode{
      treeNode *lc;
      element data;
      short int bf;
      treeNode *rc;
    };
    

    Tree's depth can be found out using

    int depth(treeNode *p){
        if(p==NULL) return 0;
        int l=depth(p->lc);
        int r=depth(p->rc);
        if(l>=r)
            return l+1;
        else
            return r+1;
    }
    

    below gotoxy function moves your cursor to the desired position

    void gotoxy(int x,int y)
    {
    printf("%c[%d;%df",0x1B,y,x);
    }
    

    Then Printing a Tree can be done as:

    void displayTreeUpDown(treeNode * root,int x,int y,int px=0){
    if(root==NULL) return;
    gotoxy(x,y);
    int a=abs(px-x)/2;
    cout<<root->data.key;
    displayTreeUpDown(root->lc,x-a,y+1,x);
    displayTreeUpDown(root->rc,x+a,y+1,x);
    }
    

    which can be called using:

    display(t,pow(2,depth(t)),1,1);
    
    0 讨论(0)
  • 2020-11-28 22:46

    It's never going to be pretty enough, unless one does some backtracking to re-calibrate the display output. But one can emit pretty enough binary trees efficiently using heuristics: Given the height of a tree, one can guess what the expected width and setw of nodes at different depths. There are a few pieces needed to do this, so let's start with the higher level functions first to provide context.

    The pretty print function:

       // create a pretty vertical tree
       void postorder(Node *p)
       {
          int height = getHeight(p) * 2;
          for (int i = 0 ; i < height; i ++) {
             printRow(p, height, i);
          }
       }
    

    The above code is easy. The main logic is in the printRow function. Let's delve into that.

    void printRow(const Node *p, const int height, int depth)
    {
            vector<int> vec;
            getLine(p, depth, vec);
            cout << setw((height - depth)*2); // scale setw with depth
            bool toggle = true; // start with left
            if (vec.size() > 1) {
                    for (int v : vec) {
                            if (v != placeholder) {
                                    if (toggle)
                                            cout << "/" << "   ";
                                    else
                                            cout << "\\" << "   ";
                            }
                            toggle = !toggle;
                    }
                    cout << endl;
                    cout << setw((height - depth)*2);
            }
            for (int v : vec) {
                    if (v != placeholder)
                            cout << v << "   ";
            }
            cout << endl;
    }
    

    getLine() does what you'd expect: it stores all nodes with a given equal depth into vec. Here's the code for that:

    void getLine(const Node *root, int depth, vector<int>& vals)
    {
            if (depth <= 0 && root != nullptr) {
                    vals.push_back(root->val);
                    return;
            }
            if (root->left != nullptr)
                    getLine(root->left, depth-1, vals);
            else if (depth-1 <= 0)
                    vals.push_back(placeholder);
            if (root->right != nullptr)
                    getLine(root->right, depth-1, vals);
            else if (depth-1 <= 0)
                    vals.push_back(placeholder);
    }
    

    Now back to printRow(). For each line, we set the stream width based on how deep we are in the binary tree. This formatting will be nice because, typically, the deeper you go, the more width is needed. I say typically because in degenerate trees, this wouldn't look as pretty. As long as the tree is roughly balanced and smallish (< 20 items), it should turn out fine. A placeholder is needed to align the '/' and '\' characters properly. So when a row is obtained via getLine(), we insert the placeholder if there isn't any node present at the specified depth. The placeholder can be set to anything like (1<<31) for example. Obviously, this isn't robust because the placeholder could be a valid node value. If a coder's got spunk and is only dealing with decimals, one could modify the code to emit decimal-converted strings via getLine() and use a placeholder like "_". (Unfortunately, I'm not such a coder :P)

    The result for the following items inserted in order: 8, 12, 4, 2, 5, 15 is

           8   
         /   \   
         4   12   
       /   \   \   
       2   5   15   
    

    getHeight() is left to the reader as an exercise. :) One could even get prettier results by retroactively updating the setw of shallow nodes based on the number of items in deeper nodes. That too is left to the reader as an exercise.

    0 讨论(0)
  • 2020-11-28 22:47
        //Binary tree (pretty print):
        //                        ________________________50______________________                        
        //            ____________30                                  ____________70__________            
        //      ______20____                                          60                ______90          
        //      10          15                                                          80                
    
    
        // prettyPrint
        public static void prettyPrint(BTNode node) {
            // get height first
            int height = heightRecursive(node);
    
            // perform  level order traversal
            Queue<BTNode> queue = new LinkedList<BTNode>();
    
            int level = 0;
            final int SPACE = 6;
            int nodePrintLocation = 0;
    
            // special node for pushing when a node has no left or right child (assumption, say this node is a node with value Integer.MIN_VALUE)
            BTNode special = new BTNode(Integer.MIN_VALUE);
    
            queue.add(node);
            queue.add(null);    // end of level 0
            while(! queue.isEmpty()) {
                node = queue.remove();
    
                if (node == null) {
                    if (!queue.isEmpty()) {
                        queue.add(null);
                    }
    
                    // start of new level
                    System.out.println();
                    level++;
                } else {
                    nodePrintLocation = ((int) Math.pow(2, height - level)) * SPACE;
    
                    System.out.print(getPrintLine(node, nodePrintLocation));
    
                    if (level < height) {
                        // only go till last level
                        queue.add((node.left != null) ? node.left : special);
                        queue.add((node.right != null) ? node.right : special);
                    }
                }
            }       
        }
        public void prettyPrint() {
            System.out.println("\nBinary tree (pretty print):");
            prettyPrint(root);
        }
        private static String getPrintLine(BTNode node, int spaces) {
            StringBuilder sb = new StringBuilder();
    
            if (node.data == Integer.MIN_VALUE) {
                // for child nodes, print spaces
                for (int i = 0; i < 2 * spaces; i++) {
                    sb.append(" ");
                }
    
                return sb.toString();
            }
    
            int i = 0;
            int to = spaces/2;
    
            for (; i < to; i++) {
                sb.append(' ');
            }
            to += spaces/2;
            char ch = ' ';
            if (node.left != null) {
                ch = '_';
            }
            for (; i < to; i++) {
                sb.append(ch);
            }
    
            String value = Integer.toString(node.data);
            sb.append(value);
    
            to += spaces/2;
            ch = ' ';
            if (node.right != null) {
                ch = '_';
            }
            for (i += value.length(); i < to; i++) {
                sb.append(ch);
            }
    
            to += spaces/2;
            for (; i < to; i++) {
                sb.append(' ');
            }
    
            return sb.toString();
        }
    
        private static int heightRecursive(BTNode  node) {
            if (node == null) {
                // empty tree
                return -1;
            }
    
            if (node.left == null && node.right == null) {
                // leaf node
                return 0;
            }
    
            return 1 + Math.max(heightRecursive(node.left), heightRecursive(node.right));
        }
    
    0 讨论(0)
  • 2020-11-28 22:48

    If your only need is to visualize your tree, a better method would be to output it into a dot format and draw it with grapviz.

    You can look at dot guide for more information abt syntax etc

    0 讨论(0)
提交回复
热议问题