简体   繁体   中英

Printing rows of binary tree recursively?

I'm learning data structures on my own because they don't teach electrical engineers that stuff in school. I want to have a tool to print the rows of a tree so I can see what I'm traversing as I debug. Here's my iterative solution for printing a row, finding everything in the next row, and repeating. I feel like I should be doing this recursively but don't know how to get an output of rows, and I'd also like to make it easier to read than the left aligned output this produces. I'd also like to avoid adding a parent field to my tree nodes. Any advice?

void printtree(ibtreenode * root){
    binodqueue * printbuff = new binodqueue;
    binodqueue * searchbuff = new binodqueue;
    printbuff->enqueue(root);
    int row = 0;
    while(!printbuff->isempty()){
        ibtreenode * current = printbuff->dequeue();
        if(current->left!=NULL)
            searchbuff->enqueue(current->left);
        if(current->right!=NULL)
            searchbuff->enqueue(current->right);
        printf(" %d ",current->data);
        if(printbuff->isempty()){
            printf("-- row %d\n",row);
            row++;
            while (!searchbuff->isempty()){
                printbuff->enqueue(searchbuff->dequeue());
            }
        }
    }
}

For reference: binodqueue is a queue which holds and returns binary tree nodes and ibtreenode is the name of my binary tree nodes holding ints.

Basic idea is to print the tree by traversing DFS and writing each node into a line of text. Putting some sort of prefix for each node below the root node ensures a visible structure.

The recursion is pretty basic...

  • Make sure to have a recursion anchor: something that is guaranteed to happen after some number of recursive calls and that doesn't trigger another recursion
  • Handle your current node
  • Make sure to recurse into each sub-node

code:

// print whatever you deem adequate as prefix before a node for a given level in the tree
void printprefix(int level) {
    for (int i = 0; i < level - 1; ++i)
        printf("  ");
    
    if (level > 0)
        printf("- ");
}

// recursive tree printing function
void printtree(ibtreenode * root, int level = 0){
    // recursion anchor
    if (root == NULL)
        return;
    
    // print current level
    printprefix(level); 
    printf("%d\n",current->data);

    // recurse sub-tree
    printtree(root->left, level + 1);
    printtree(root->right, level + 1);
}

Code might contain stupid syntax errors, since I have no C++ compiler at hand while writing this.


If you want nicely formatted visual output you could also decide to write your tree to a file and then use some tool like https://graphviz.org/ to convert the output to an actual image. If you are interested in an approach to write an input file for the graphviz dot format, I could expand my answer.

I would first recursively build a vector of rows, each row being a vector of pairs data - position_in_the_tree. This part is easy with an in order traversal of the tree.

Then I would use that vector to print each row knowing the position of the node in the tree .

Code could be:

// recursively builds the vector of rows
void buildrows(ibtreenode* root,
    std::vector < std::vector<std::pair<int, unsigned> > >& rows,
    unsigned & pos, unsigned level) {
    if (root == nullptr) return;
    if (level >= rows.size()) {    // need to add a new row
        rows.push_back(std::vector<std::pair<int, unsigned> >());
    }
    buildrows(root->left, rows, pos, level + 1);
    std::pair<int, unsigned> p{ root->data, pos++ }; // here is pos handling
    rows[level].push_back(p);
    buildrows(root->right, rows, pos, level + 1);
}

/* root is the tree to print, width is the width used to print a value */
void printtree(ibtreenode* root, size_t width) {
    std::vector < std::vector<std::pair<int, unsigned> > > rows;
    unsigned pos = 0;   // the position in the tree
    buildrows(root, rows, pos, 0);
    for (auto& row : rows) {
        pos = 0;
        for (auto& it : row) {
            unsigned delta = 1 + it.second - pos;
            std::cout << std::setw(delta * width) << it.first ;
            pos = it.second + 1;
        }
        std::cout << '\n';
    }
}

With a trivial tree I could get (with width = 2):

       4
   2       6
 1   3   5   7

and (after removing the 5 node):

       4
   2     6
 1   3     7

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM