Print binary tree in a pretty way using c++ - c++

I am a "bit" lost trying to print a binary tree like below in c++:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
I know how to get the height of the tree and the number of nodes in each level, but I couldn't figure out how to set the right number of spaces between the root and the second level (there are 3 lines under the root for 3 levels but I believe it is not this everytime,I thought it could be 3 times the height for greater trees).
I would like to have some help to print these spaces in the rows and the number of lines between the rows.Thank you.
I am coding in c++
Get height
int tree::getHeight(No *node) {
if (node == NULL) return 0;
return 1 + max(getHeight(node->esq), getHeight(node->dir));
}
Get number of nodes per line
void tree::getLine(const No *root, int depth, vector<int>& vals){
int placeholder = 10;
if (depth <= 0 && root != nullptr) {
vals.push_back(root->chave);
return;
}
if (root->esq != nullptr)
getLine(root->esq, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
if (root->dir != nullptr)
getLine(root->dir, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
}

Even tough it is not exactly what you asked for, printing trees horizontally is way simpler. And especially in case of large trees, I think this is the better representation form.
└──8
├──5
│ ├──2
│ └──6
└──10
├──9
└──11
Following C++ code roots in this java implementation.
void printBT(const std::string& prefix, const BSTNode* node, bool isLeft)
{
if( node != nullptr )
{
std::cout << prefix;
std::cout << (isLeft ? "├──" : "└──" );
// print the value of the node
std::cout << node->m_val << std::endl;
// enter the next tree level - left and right branch
printBT( prefix + (isLeft ? "│ " : " "), node->m_left, true);
printBT( prefix + (isLeft ? "│ " : " "), node->m_right, false);
}
}
void printBT(const BSTNode* node)
{
printBT("", node, false);
}
// pass the root node of your binary tree
printBT(root);

Here is an example of code creating a text-based representation of a binary tree. This demonstration uses a minimally useful binary tree class (BinTree), with a small footprint, just to avoid bloating the example's size.
Its text-rendering member functions are more serious, using iteration rather than recursion, as found in other parts of the class.
This does its job in three steps, first a vector of rows of string values is put together.
Then this is used to format lines of text strings representing the tree.
Then the strings are cleaned up and dumped to cout.
As an added bonus, the demo includes a "random tree" feature, for hours of nonstop entertainment.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <random>
using std::vector;
using std::string;
using std::cout;
template <typename T>
class BinTree {
struct Node {
T value;
Node *left,*right;
Node() : left(nullptr),right(nullptr) {}
Node(const T& value) :value(value),left(nullptr),right(nullptr) {}
// stack-abusing recursion everywhere, for small code
~Node() { delete left; delete right; }
int max_depth() const {
const int left_depth = left ? left->max_depth() : 0;
const int right_depth = right ? right->max_depth() : 0;
return (left_depth > right_depth ? left_depth : right_depth) + 1;
}
};
Node *root;
public:
BinTree() : root(nullptr) {}
~BinTree() { delete root; }
int get_max_depth() const { return root ? root->max_depth() : 0; }
void clear() { delete root; root = nullptr; }
void insert() {}
template <typename ...Args>
void insert(const T& value, Args...more) {
if(!root) {
root = new Node(value);
} else {
Node* p = root;
for(;;) {
if(value == p->value) return;
Node* &pchild = value < p->value ? p->left : p->right;
if(!pchild) {
pchild = new Node(value);
break;
}
p = pchild;
}
}
insert(more...);
}
struct cell_display {
string valstr;
bool present;
cell_display() : present(false) {}
cell_display(std::string valstr) : valstr(valstr), present(true) {}
};
using display_rows = vector< vector< cell_display > >;
// The text tree generation code below is all iterative, to avoid stack faults.
// get_row_display builds a vector of vectors of cell_display structs
// each vector of cell_display structs represents one row, starting at the root
display_rows get_row_display() const {
// start off by traversing the tree to
// build a vector of vectors of Node pointers
vector<Node*> traversal_stack;
vector< std::vector<Node*> > rows;
if(!root) return display_rows();
Node *p = root;
const int max_depth = root->max_depth();
rows.resize(max_depth);
int depth = 0;
for(;;) {
// Max-depth Nodes are always a leaf or null
// This special case blocks deeper traversal
if(depth == max_depth-1) {
rows[depth].push_back(p);
if(depth == 0) break;
--depth;
continue;
}
// First visit to node? Go to left child.
if(traversal_stack.size() == depth) {
rows[depth].push_back(p);
traversal_stack.push_back(p);
if(p) p = p->left;
++depth;
continue;
}
// Odd child count? Go to right child.
if(rows[depth+1].size() % 2) {
p = traversal_stack.back();
if(p) p = p->right;
++depth;
continue;
}
// Time to leave if we get here
// Exit loop if this is the root
if(depth == 0) break;
traversal_stack.pop_back();
p = traversal_stack.back();
--depth;
}
// Use rows of Node pointers to populate rows of cell_display structs.
// All possible slots in the tree get a cell_display struct,
// so if there is no actual Node at a struct's location,
// its boolean "present" field is set to false.
// The struct also contains a string representation of
// its Node's value, created using a std::stringstream object.
display_rows rows_disp;
std::stringstream ss;
for(const auto& row : rows) {
rows_disp.emplace_back();
for(Node* pn : row) {
if(pn) {
ss << pn->value;
rows_disp.back().push_back(cell_display(ss.str()));
ss = std::stringstream();
} else {
rows_disp.back().push_back(cell_display());
} } }
return rows_disp;
}
// row_formatter takes the vector of rows of cell_display structs
// generated by get_row_display and formats it into a test representation
// as a vector of strings
vector<string> row_formatter(const display_rows& rows_disp) const {
using s_t = string::size_type;
// First find the maximum value string length and put it in cell_width
s_t cell_width = 0;
for(const auto& row_disp : rows_disp) {
for(const auto& cd : row_disp) {
if(cd.present && cd.valstr.length() > cell_width) {
cell_width = cd.valstr.length();
} } }
// make sure the cell_width is an odd number
if(cell_width % 2 == 0) ++cell_width;
// allows leaf nodes to be connected when they are
// all with size of a single character
if(cell_width < 3) cell_width = 3;
// formatted_rows will hold the results
vector<string> formatted_rows;
// some of these counting variables are related,
// so its should be possible to eliminate some of them.
s_t row_count = rows_disp.size();
// this row's element count, a power of two
s_t row_elem_count = 1 << (row_count-1);
// left_pad holds the number of space charactes at the beginning of the bottom row
s_t left_pad = 0;
// Work from the level of maximum depth, up to the root
// ("formatted_rows" will need to be reversed when done)
for(s_t r=0; r<row_count; ++r) {
const auto& cd_row = rows_disp[row_count-r-1]; // r reverse-indexes the row
// "space" will be the number of rows of slashes needed to get
// from this row to the next. It is also used to determine other
// text offsets.
s_t space = (s_t(1) << r) * (cell_width + 1) / 2 - 1;
// "row" holds the line of text currently being assembled
string row;
// iterate over each element in this row
for(s_t c=0; c<row_elem_count; ++c) {
// add padding, more when this is not the leftmost element
row += string(c ? left_pad*2+1 : left_pad, ' ');
if(cd_row[c].present) {
// This position corresponds to an existing Node
const string& valstr = cd_row[c].valstr;
// Try to pad the left and right sides of the value string
// with the same number of spaces. If padding requires an
// odd number of spaces, right-sided children get the longer
// padding on the right side, while left-sided children
// get it on the left side.
s_t long_padding = cell_width - valstr.length();
s_t short_padding = long_padding / 2;
long_padding -= short_padding;
row += string(c%2 ? short_padding : long_padding, ' ');
row += valstr;
row += string(c%2 ? long_padding : short_padding, ' ');
} else {
// This position is empty, Nodeless...
row += string(cell_width, ' ');
}
}
// A row of spaced-apart value strings is ready, add it to the result vector
formatted_rows.push_back(row);
// The root has been added, so this loop is finsished
if(row_elem_count == 1) break;
// Add rows of forward- and back- slash characters, spaced apart
// to "connect" two rows' Node value strings.
// The "space" variable counts the number of rows needed here.
s_t left_space = space + 1;
s_t right_space = space - 1;
for(s_t sr=0; sr<space; ++sr) {
string row;
for(s_t c=0; c<row_elem_count; ++c) {
if(c % 2 == 0) {
row += string(c ? left_space*2 + 1 : left_space, ' ');
row += cd_row[c].present ? '/' : ' ';
row += string(right_space + 1, ' ');
} else {
row += string(right_space, ' ');
row += cd_row[c].present ? '\\' : ' ';
}
}
formatted_rows.push_back(row);
++left_space;
--right_space;
}
left_pad += space + 1;
row_elem_count /= 2;
}
// Reverse the result, placing the root node at the beginning (top)
std::reverse(formatted_rows.begin(), formatted_rows.end());
return formatted_rows;
}
// Trims an equal number of space characters from
// the beginning of each string in the vector.
// At least one string in the vector will end up beginning
// with no space characters.
static void trim_rows_left(vector<string>& rows) {
if(!rows.size()) return;
auto min_space = rows.front().length();
for(const auto& row : rows) {
auto i = row.find_first_not_of(' ');
if(i==string::npos) i = row.length();
if(i == 0) return;
if(i < min_space) min_space = i;
}
for(auto& row : rows) {
row.erase(0, min_space);
} }
// Dumps a representation of the tree to cout
void Dump() const {
const int d = get_max_depth();
// If this tree is empty, tell someone
if(d == 0) {
cout << " <empty tree>\n";
return;
}
// This tree is not empty, so get a list of node values...
const auto rows_disp = get_row_display();
// then format these into a text representation...
auto formatted_rows = row_formatter(rows_disp);
// then trim excess space characters from the left sides of the text...
trim_rows_left(formatted_rows);
// then dump the text to cout.
for(const auto& row : formatted_rows) {
std::cout << ' ' << row << '\n';
}
}
};
int main() {
BinTree<int> bt;
// Build OP's tree
bt.insert(8,5,2,6,10,9,11);
cout << "Tree from OP:\n\n";
bt.Dump();
cout << "\n\n";
bt.clear();
// Build a random tree
// This toy tree can't balance, so random
// trees often look more like linked lists.
// Just keep trying until a nice one shows up.
std::random_device rd;
std::mt19937 rng(rd());
int MaxCount=20;
int MaxDepth=5;
const int Min=0, Max=1000;
std::uniform_int_distribution<int> dist(Min,Max);
while(MaxCount--) {
bt.insert(dist(rng));
if(bt.get_max_depth() >= MaxDepth) break;
}
cout << "Randomly generated tree:\n\n";
bt.Dump();
}
An example of the output:
Tree from OP:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
Randomly generated tree:
703
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
137 965
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
41 387 786
\ / \ / \
\ / \ / \
\ / \ / \
95 382 630 726 813
\
841

I wrote arbitrary tree pretty printer as a part of C++ algorithms self-education.
The approach is following.
From each tree node printable node with stringified original node value and absolute position in the line composed.
Sibling printable nodes grouped. Each sibling group contains list of nodes and pointer to parent printable node.
Sibling groups grouped to lines, each line represents original tree level.
Next, printable nodes position are calculated.
Lines iterated through skipping first one.
Siblings in the line iterated, each sibling group moved to its parent node center if the center is further then the middle of the group. It moves even further if intersected with previous siblings group. Parent node moved to the middle of the children nodes if the middle is further than parent center. Nodes following parent node are shifted if intersected with shifted parent node.
Previous step repeated for siblings group parent siblings group recursively.
For the last step lines iterated once again to be written to the provided output stream, filling with spaces offsets according to the calculated nodes positions.
Unix box-drawing symbols are used to draw lines. Not sure if they will be printed correctly in Windows cmd, maybe they should be replaced by their DOS counterparts for Windows.
1
┌────────────┬────────┴────────────────────┐
11 12 13
┌────┼────┐ ┌──┴─┐ ┌─────────┴────┬────┐
111 112 113 121 122 131 132 133
┌─────┼─────┐ ┌─────┼─────┐ ┌──┴──┐
1221 1222 1223 1311 1312 1313 1321 1322
Unit tests with usage samples

I updated the vertical output again, the tree view was mirrored and some characters were not accepted in VS, so i put them in UTF8:
void printBT(const std::string& prefix, const TreeNode* node, bool isLeft)
{
if (node != nullptr)
{
std::cout << prefix;
std::cout << (isLeft ? "|--" : "L--");
// print the value of the node
std::cout << node->val << std::endl;
// enter the next tree level - left and right branch
printBT(prefix + (isLeft ? "| " : " "), node->right, true);
printBT(prefix + (isLeft ? "| " : " "), node->left, false);
}
}
void printBT(const TreeNode* node)
{
printBT("", node, false);
}
Thanks a lot for that solution!!
Example of Nodes: { 3, 5, 1, 6, 2, 9, 8, NULL, NULL, 7, 4 };
L--3
|--1
| |--8
| L--9
L--5
|--2
| |--4
| L--7
L--6
Not soo pretty, but very handy!
Cheers Michael

1st function - prints level by level (root lv -> leaves lv)
2nd function - distance from the beginning of new line
3rd function - prints nodes and calculates distance between two prints;
void Tree::TREEPRINT()
{
int i = 0;
while (i <= treeHeight(getroot())){
printlv(i);
i++;
cout << endl;
}
}
void Tree::printlv(int n){
Node* temp = getroot();
int val = pow(2, treeHeight(root) -n+2);
cout << setw(val) << "";
prinlv(temp, n, val);
}
void Tree::dispLV(Node*p, int lv, int d)
{
int disp = 2 * d;
if (lv == 0){
if (p == NULL){
cout << " x ";
cout << setw(disp -3) << "";
return;
}
else{
int result = ((p->key <= 1) ? 1 : log10(p->key) + 1);
cout << " " << p->key << " ";
cout << setw(disp - result-2) << "";
}
}
else
{
if (p == NULL&& lv >= 1){
dispLV(NULL, lv - 1, d);
dispLV(NULL, lv - 1, d);
}
else{
dispLV(p->left, lv - 1, d);
dispLV(p->right, lv - 1, d);
}
}
}
Input:
50-28-19-30-29-17-42-200-160-170-180-240-44-26-27
Output:

I've edited the solution of Adrian Schneider and made the output more specific to understand better.
void print() {
print("", root, false, true);
}
void print(const string &prefix, Node *parent, bool isLeft, bool isRoot) {
if (parent == nullptr)
return;
if (isRoot) {
cout << "─────";
} else {
cout << prefix <<
(isLeft ? "L├────" : "R└───");
}
cout << parent -> value << endl;
print(prefix + (isLeft ? " │ " : " "),
parent -> left, true, false);
print(prefix + (isLeft ? " │ " : " "),
parent -> right, false, false);
}
The output looks like this for the input: {5, 6, 3, 2, 7}
─────5
L├────3
│ L├────2
R└───6
R└───7

Related

C++ How to find the longest possible combination of decreasing numbers in an array

I am working on a problem in which I'm given a list of numbers representing the diameter of cake layers (for example: 9 12 10 7 4 6 11 5). With this list, I have to find the length of the longest combination of numbers that are equal to or decreasing (stacking cake layers from greatest diameter at the bottom to smallest at the top). You are allowed to skip over numbers, but you can't come back to them. I.e. with the previous list, the length of the longest combination would be 5 with the combination being (12,10,7,6,5).
I believe that the best way to solve this would be feeding the array into a tree and returning the height of the tree. This is currently the code I have, with a working tree implementation above the main
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string sizeInput, transfer; //Strings to hold input and transfer to array
int maxLayers = 0, numOfInputs = 0, numNodes = 0; //ints for holding the max height and the number of inputs by the user
int cakeSizes [30]; //Array holding sizes of the cakes input, no more than 30
cout << "Cake sizes: ";
getline(cin,sizeInput); //Gets input from user and puts into a stringstream
stringstream readInput(sizeInput);
while(readInput >> transfer)
{
cakeSizes[numOfInputs] = stoi(transfer); //Puts the numbers into the array and counts how many were placed
numOfInputs++;
}
for(int i=0; i<numOfInputs; i++) //Puts the array into a tree
{
Tree<int> cakeStack; //Creates tree to hold combination
initialize(cakeStack);
for(int j=i; j<numOfInputs; j++)
{
if(cakeSizes[j]<=cakeSizes[j-1])
{
insert(cakeStack, cakeSizes[j]);
}
}
if(height(cakeStack) > maxLayers) //Checks if the new combination tree's height is greater than the last
{
maxLayers = height(cakeStack);
}
destroy(cakeStack); //Destroys the tree from the previous combination in preparation for new one
}
cout << endl << "You can build a cake with " << maxLayers << " layers.";
}
This actually works for combinations that are always decreasing (like 5,4,2,1 and 8,3,2,1), but it fails when interrupting numbers are thrown in (like with 5,4,2,8,1). I'm almost certain that the problem lies here:
for(int j=i; j<numOfInputs; j++)
{
if(cakeSizes[j]<=cakeSizes[j-1])
{
insert(cakeStack, cakeSizes[j]);
}
}
But I'm unsure of how to implement it an a way that checks all combinations of the array (like skipping numbers that wouldn't give the longest combination), rather than running straight down the list unable to skip numbers.
The tree is definitely the way to go. You build the tree by inserting each value under the smallest node larger than it. Then when the tree is finished you iterate through it looking for the longest path.
What I did in the code below is I made a head node to store the sub trees and it needed a really large value so that all the inputs would fit under it. But then when I print the tree or look for a path I need to ignore that head node, so I have to keep track of the depth.
#include <iostream>
#include <vector>
#include <climits>
struct Tree {
Tree(int value) : value(value) {}
int value;
std::vector<Tree> children;
};
// Recursively check this level of the tree
void insert_node(Tree& node, int value)
{
// if the new value is bigger than where
// we are then stop descending
if (value > node.value)
return;
// if the new value fits under this
// parent then check all the children
bool inserted = false;
for (Tree& child : node.children)
// if we find a child large enough
// then insert ourselves inside
if (value < child.value)
{
insert_node(child, value);
inserted = true;
}
// if the new value fits under this parent but
// not under any of the children then put it here
if (!inserted)
node.children.push_back(value);
}
void print_tree(Tree node,
std::vector<bool> flags = std::vector<bool>(100, true),
bool last = false,
int depth = 0)
{
for (int i = 1; i < depth; ++i)
{
if (flags[i])
std::cout << "| ";
else
std::cout << " ";
}
// Don't print our fake head
if (depth > 0)
{
std::cout << "+- " << node.value << '\n';
if (last) flags[depth] = false;
}
int n = 0;
for (Tree child : node.children)
{
last = (n++ == node.children.size() - 1);
print_tree(child, flags, last, depth + 1);
}
flags[depth] = true;
}
void print_path(std::vector<int> path)
{
std::cout << "Path:";
for (int value : path)
std::cout << " " << value;
std::cout << "\n";
}
void print_paths(Tree node,
std::vector<int>& max_path,
std::vector<int> path = std::vector<int>(),
int depth = 0)
{
// Don't add our fake head
if (depth > 0)
path.push_back(node.value);
if (node.children.size() == 0)
{
print_path(path);
// check if this path is the longest one yet
if (max_path.size() < path.size())
max_path = path;
}
for (Tree child : node.children)
print_paths(child, max_path, path, depth + 1);
}
int main()
{
Tree head(INT_MAX);
std::vector<int> input = {9, 12, 10, 7, 4, 6, 11, 5};
// Build the tree
for (int value : input)
insert_node(head, value);
// Print the tree
std::cout << "Tree:\n";
print_tree(head);
std::cout << "\n";
// Print the paths and
// find the longest one
// and then print it too
std::vector<int> max_path;
print_paths(head, max_path);
std::cout << "\nLongest ";
print_path(max_path);
return 0;
}

How do I print a binary tree “as a” tree? [duplicate]

I am a "bit" lost trying to print a binary tree like below in c++:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
I know how to get the height of the tree and the number of nodes in each level, but I couldn't figure out how to set the right number of spaces between the root and the second level (there are 3 lines under the root for 3 levels but I believe it is not this everytime,I thought it could be 3 times the height for greater trees).
I would like to have some help to print these spaces in the rows and the number of lines between the rows.Thank you.
I am coding in c++
Get height
int tree::getHeight(No *node) {
if (node == NULL) return 0;
return 1 + max(getHeight(node->esq), getHeight(node->dir));
}
Get number of nodes per line
void tree::getLine(const No *root, int depth, vector<int>& vals){
int placeholder = 10;
if (depth <= 0 && root != nullptr) {
vals.push_back(root->chave);
return;
}
if (root->esq != nullptr)
getLine(root->esq, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
if (root->dir != nullptr)
getLine(root->dir, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
}
Even tough it is not exactly what you asked for, printing trees horizontally is way simpler. And especially in case of large trees, I think this is the better representation form.
└──8
├──5
│ ├──2
│ └──6
└──10
├──9
└──11
Following C++ code roots in this java implementation.
void printBT(const std::string& prefix, const BSTNode* node, bool isLeft)
{
if( node != nullptr )
{
std::cout << prefix;
std::cout << (isLeft ? "├──" : "└──" );
// print the value of the node
std::cout << node->m_val << std::endl;
// enter the next tree level - left and right branch
printBT( prefix + (isLeft ? "│ " : " "), node->m_left, true);
printBT( prefix + (isLeft ? "│ " : " "), node->m_right, false);
}
}
void printBT(const BSTNode* node)
{
printBT("", node, false);
}
// pass the root node of your binary tree
printBT(root);
Here is an example of code creating a text-based representation of a binary tree. This demonstration uses a minimally useful binary tree class (BinTree), with a small footprint, just to avoid bloating the example's size.
Its text-rendering member functions are more serious, using iteration rather than recursion, as found in other parts of the class.
This does its job in three steps, first a vector of rows of string values is put together.
Then this is used to format lines of text strings representing the tree.
Then the strings are cleaned up and dumped to cout.
As an added bonus, the demo includes a "random tree" feature, for hours of nonstop entertainment.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <random>
using std::vector;
using std::string;
using std::cout;
template <typename T>
class BinTree {
struct Node {
T value;
Node *left,*right;
Node() : left(nullptr),right(nullptr) {}
Node(const T& value) :value(value),left(nullptr),right(nullptr) {}
// stack-abusing recursion everywhere, for small code
~Node() { delete left; delete right; }
int max_depth() const {
const int left_depth = left ? left->max_depth() : 0;
const int right_depth = right ? right->max_depth() : 0;
return (left_depth > right_depth ? left_depth : right_depth) + 1;
}
};
Node *root;
public:
BinTree() : root(nullptr) {}
~BinTree() { delete root; }
int get_max_depth() const { return root ? root->max_depth() : 0; }
void clear() { delete root; root = nullptr; }
void insert() {}
template <typename ...Args>
void insert(const T& value, Args...more) {
if(!root) {
root = new Node(value);
} else {
Node* p = root;
for(;;) {
if(value == p->value) return;
Node* &pchild = value < p->value ? p->left : p->right;
if(!pchild) {
pchild = new Node(value);
break;
}
p = pchild;
}
}
insert(more...);
}
struct cell_display {
string valstr;
bool present;
cell_display() : present(false) {}
cell_display(std::string valstr) : valstr(valstr), present(true) {}
};
using display_rows = vector< vector< cell_display > >;
// The text tree generation code below is all iterative, to avoid stack faults.
// get_row_display builds a vector of vectors of cell_display structs
// each vector of cell_display structs represents one row, starting at the root
display_rows get_row_display() const {
// start off by traversing the tree to
// build a vector of vectors of Node pointers
vector<Node*> traversal_stack;
vector< std::vector<Node*> > rows;
if(!root) return display_rows();
Node *p = root;
const int max_depth = root->max_depth();
rows.resize(max_depth);
int depth = 0;
for(;;) {
// Max-depth Nodes are always a leaf or null
// This special case blocks deeper traversal
if(depth == max_depth-1) {
rows[depth].push_back(p);
if(depth == 0) break;
--depth;
continue;
}
// First visit to node? Go to left child.
if(traversal_stack.size() == depth) {
rows[depth].push_back(p);
traversal_stack.push_back(p);
if(p) p = p->left;
++depth;
continue;
}
// Odd child count? Go to right child.
if(rows[depth+1].size() % 2) {
p = traversal_stack.back();
if(p) p = p->right;
++depth;
continue;
}
// Time to leave if we get here
// Exit loop if this is the root
if(depth == 0) break;
traversal_stack.pop_back();
p = traversal_stack.back();
--depth;
}
// Use rows of Node pointers to populate rows of cell_display structs.
// All possible slots in the tree get a cell_display struct,
// so if there is no actual Node at a struct's location,
// its boolean "present" field is set to false.
// The struct also contains a string representation of
// its Node's value, created using a std::stringstream object.
display_rows rows_disp;
std::stringstream ss;
for(const auto& row : rows) {
rows_disp.emplace_back();
for(Node* pn : row) {
if(pn) {
ss << pn->value;
rows_disp.back().push_back(cell_display(ss.str()));
ss = std::stringstream();
} else {
rows_disp.back().push_back(cell_display());
} } }
return rows_disp;
}
// row_formatter takes the vector of rows of cell_display structs
// generated by get_row_display and formats it into a test representation
// as a vector of strings
vector<string> row_formatter(const display_rows& rows_disp) const {
using s_t = string::size_type;
// First find the maximum value string length and put it in cell_width
s_t cell_width = 0;
for(const auto& row_disp : rows_disp) {
for(const auto& cd : row_disp) {
if(cd.present && cd.valstr.length() > cell_width) {
cell_width = cd.valstr.length();
} } }
// make sure the cell_width is an odd number
if(cell_width % 2 == 0) ++cell_width;
// allows leaf nodes to be connected when they are
// all with size of a single character
if(cell_width < 3) cell_width = 3;
// formatted_rows will hold the results
vector<string> formatted_rows;
// some of these counting variables are related,
// so its should be possible to eliminate some of them.
s_t row_count = rows_disp.size();
// this row's element count, a power of two
s_t row_elem_count = 1 << (row_count-1);
// left_pad holds the number of space charactes at the beginning of the bottom row
s_t left_pad = 0;
// Work from the level of maximum depth, up to the root
// ("formatted_rows" will need to be reversed when done)
for(s_t r=0; r<row_count; ++r) {
const auto& cd_row = rows_disp[row_count-r-1]; // r reverse-indexes the row
// "space" will be the number of rows of slashes needed to get
// from this row to the next. It is also used to determine other
// text offsets.
s_t space = (s_t(1) << r) * (cell_width + 1) / 2 - 1;
// "row" holds the line of text currently being assembled
string row;
// iterate over each element in this row
for(s_t c=0; c<row_elem_count; ++c) {
// add padding, more when this is not the leftmost element
row += string(c ? left_pad*2+1 : left_pad, ' ');
if(cd_row[c].present) {
// This position corresponds to an existing Node
const string& valstr = cd_row[c].valstr;
// Try to pad the left and right sides of the value string
// with the same number of spaces. If padding requires an
// odd number of spaces, right-sided children get the longer
// padding on the right side, while left-sided children
// get it on the left side.
s_t long_padding = cell_width - valstr.length();
s_t short_padding = long_padding / 2;
long_padding -= short_padding;
row += string(c%2 ? short_padding : long_padding, ' ');
row += valstr;
row += string(c%2 ? long_padding : short_padding, ' ');
} else {
// This position is empty, Nodeless...
row += string(cell_width, ' ');
}
}
// A row of spaced-apart value strings is ready, add it to the result vector
formatted_rows.push_back(row);
// The root has been added, so this loop is finsished
if(row_elem_count == 1) break;
// Add rows of forward- and back- slash characters, spaced apart
// to "connect" two rows' Node value strings.
// The "space" variable counts the number of rows needed here.
s_t left_space = space + 1;
s_t right_space = space - 1;
for(s_t sr=0; sr<space; ++sr) {
string row;
for(s_t c=0; c<row_elem_count; ++c) {
if(c % 2 == 0) {
row += string(c ? left_space*2 + 1 : left_space, ' ');
row += cd_row[c].present ? '/' : ' ';
row += string(right_space + 1, ' ');
} else {
row += string(right_space, ' ');
row += cd_row[c].present ? '\\' : ' ';
}
}
formatted_rows.push_back(row);
++left_space;
--right_space;
}
left_pad += space + 1;
row_elem_count /= 2;
}
// Reverse the result, placing the root node at the beginning (top)
std::reverse(formatted_rows.begin(), formatted_rows.end());
return formatted_rows;
}
// Trims an equal number of space characters from
// the beginning of each string in the vector.
// At least one string in the vector will end up beginning
// with no space characters.
static void trim_rows_left(vector<string>& rows) {
if(!rows.size()) return;
auto min_space = rows.front().length();
for(const auto& row : rows) {
auto i = row.find_first_not_of(' ');
if(i==string::npos) i = row.length();
if(i == 0) return;
if(i < min_space) min_space = i;
}
for(auto& row : rows) {
row.erase(0, min_space);
} }
// Dumps a representation of the tree to cout
void Dump() const {
const int d = get_max_depth();
// If this tree is empty, tell someone
if(d == 0) {
cout << " <empty tree>\n";
return;
}
// This tree is not empty, so get a list of node values...
const auto rows_disp = get_row_display();
// then format these into a text representation...
auto formatted_rows = row_formatter(rows_disp);
// then trim excess space characters from the left sides of the text...
trim_rows_left(formatted_rows);
// then dump the text to cout.
for(const auto& row : formatted_rows) {
std::cout << ' ' << row << '\n';
}
}
};
int main() {
BinTree<int> bt;
// Build OP's tree
bt.insert(8,5,2,6,10,9,11);
cout << "Tree from OP:\n\n";
bt.Dump();
cout << "\n\n";
bt.clear();
// Build a random tree
// This toy tree can't balance, so random
// trees often look more like linked lists.
// Just keep trying until a nice one shows up.
std::random_device rd;
std::mt19937 rng(rd());
int MaxCount=20;
int MaxDepth=5;
const int Min=0, Max=1000;
std::uniform_int_distribution<int> dist(Min,Max);
while(MaxCount--) {
bt.insert(dist(rng));
if(bt.get_max_depth() >= MaxDepth) break;
}
cout << "Randomly generated tree:\n\n";
bt.Dump();
}
An example of the output:
Tree from OP:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
Randomly generated tree:
703
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
137 965
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
41 387 786
\ / \ / \
\ / \ / \
\ / \ / \
95 382 630 726 813
\
841
I wrote arbitrary tree pretty printer as a part of C++ algorithms self-education.
The approach is following.
From each tree node printable node with stringified original node value and absolute position in the line composed.
Sibling printable nodes grouped. Each sibling group contains list of nodes and pointer to parent printable node.
Sibling groups grouped to lines, each line represents original tree level.
Next, printable nodes position are calculated.
Lines iterated through skipping first one.
Siblings in the line iterated, each sibling group moved to its parent node center if the center is further then the middle of the group. It moves even further if intersected with previous siblings group. Parent node moved to the middle of the children nodes if the middle is further than parent center. Nodes following parent node are shifted if intersected with shifted parent node.
Previous step repeated for siblings group parent siblings group recursively.
For the last step lines iterated once again to be written to the provided output stream, filling with spaces offsets according to the calculated nodes positions.
Unix box-drawing symbols are used to draw lines. Not sure if they will be printed correctly in Windows cmd, maybe they should be replaced by their DOS counterparts for Windows.
1
┌────────────┬────────┴────────────────────┐
11 12 13
┌────┼────┐ ┌──┴─┐ ┌─────────┴────┬────┐
111 112 113 121 122 131 132 133
┌─────┼─────┐ ┌─────┼─────┐ ┌──┴──┐
1221 1222 1223 1311 1312 1313 1321 1322
Unit tests with usage samples
I updated the vertical output again, the tree view was mirrored and some characters were not accepted in VS, so i put them in UTF8:
void printBT(const std::string& prefix, const TreeNode* node, bool isLeft)
{
if (node != nullptr)
{
std::cout << prefix;
std::cout << (isLeft ? "|--" : "L--");
// print the value of the node
std::cout << node->val << std::endl;
// enter the next tree level - left and right branch
printBT(prefix + (isLeft ? "| " : " "), node->right, true);
printBT(prefix + (isLeft ? "| " : " "), node->left, false);
}
}
void printBT(const TreeNode* node)
{
printBT("", node, false);
}
Thanks a lot for that solution!!
Example of Nodes: { 3, 5, 1, 6, 2, 9, 8, NULL, NULL, 7, 4 };
L--3
|--1
| |--8
| L--9
L--5
|--2
| |--4
| L--7
L--6
Not soo pretty, but very handy!
Cheers Michael
1st function - prints level by level (root lv -> leaves lv)
2nd function - distance from the beginning of new line
3rd function - prints nodes and calculates distance between two prints;
void Tree::TREEPRINT()
{
int i = 0;
while (i <= treeHeight(getroot())){
printlv(i);
i++;
cout << endl;
}
}
void Tree::printlv(int n){
Node* temp = getroot();
int val = pow(2, treeHeight(root) -n+2);
cout << setw(val) << "";
prinlv(temp, n, val);
}
void Tree::dispLV(Node*p, int lv, int d)
{
int disp = 2 * d;
if (lv == 0){
if (p == NULL){
cout << " x ";
cout << setw(disp -3) << "";
return;
}
else{
int result = ((p->key <= 1) ? 1 : log10(p->key) + 1);
cout << " " << p->key << " ";
cout << setw(disp - result-2) << "";
}
}
else
{
if (p == NULL&& lv >= 1){
dispLV(NULL, lv - 1, d);
dispLV(NULL, lv - 1, d);
}
else{
dispLV(p->left, lv - 1, d);
dispLV(p->right, lv - 1, d);
}
}
}
Input:
50-28-19-30-29-17-42-200-160-170-180-240-44-26-27
Output:
I've edited the solution of Adrian Schneider and made the output more specific to understand better.
void print() {
print("", root, false, true);
}
void print(const string &prefix, Node *parent, bool isLeft, bool isRoot) {
if (parent == nullptr)
return;
if (isRoot) {
cout << "─────";
} else {
cout << prefix <<
(isLeft ? "L├────" : "R└───");
}
cout << parent -> value << endl;
print(prefix + (isLeft ? " │ " : " "),
parent -> left, true, false);
print(prefix + (isLeft ? " │ " : " "),
parent -> right, false, false);
}
The output looks like this for the input: {5, 6, 3, 2, 7}
─────5
L├────3
│ L├────2
R└───6
R└───7

How to print a level of a binary search tree?

If we have say, a tree with a depth of 2:
6 <- depth = 0
/ \
/ \
4 9 <- depth = 1
/ \ \
3 5 10 <- depth = 2
And I only want to print the second level, so 3, 5, and 10 (in that order), how would I go about doing this? I'm using the code I wrote for my inorder traversal but I'm stuck on how to track depth of the tree and print when I'm at said depth.
void printLevelNodesHelper(MovieNode * curr, int level){ //helper function
int lvl = level; //store initial value of level
if(curr != NULL){
printLevelNodesHelper(curr->left, level+1);
if(level == lvl){
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
printLevelNodesHelper(curr->right, level+1);
}
}
void MovieTree::printLevelNodes(int k){ //k is the desired level
MovieNode * curr = root;
if(root == NULL){ //if the tree is empty exit it
return;
}
else if(k == 0){ //print the root's title
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
else{
printLevelNodesHelper(curr, k);
}
}
Here's the info for my struct and class
struct MovieNode{
int ranking;
string title;
int year;
float rating;
MovieNode* left = NULL;
MovieNode* right = NULL;
};
class MovieTree{
private:
MovieNode* root;
public:
MovieTree();
~MovieTree();
void printMovieInventory();
void addMovieNode(int ranking, std::string title, int year, float rating);
void findMovie(std::string title);
void queryMovies(float rating, int year);
void averageRating();
void printLevelNodes(int k);
};
Some issues:
As your initial call to printLevelNodesHelper gets the desired level as argument, it makes no sense to make recursive calls with level+1. Think about it: when you recur, you actually descend in the tree, coming closer to the desired level, so you should not increase the distance to that level, but decrease it. So you should pass level-1
In printLevelNodesHelper the if condition level == lvl is always going to be true, because neither of these local variables ever change value. As from the previous point we guarantee that eventually we will get a call with level equal to 0, we should check for level == 0 (and so you don't need the lvl variable).
Code:
void printLevelNodesHelper(MovieNode * curr, int level) {
if (curr != NULL) {
printLevelNodesHelper(curr->left, level - 1);
if (level == 0) {
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
printLevelNodesHelper(curr->right, level - 1);
}
}
With this change, the code for MovieTree::printLevelNodes does not need to deal with the boundary cases of root == NULL or k == 0. Both of these are well managed in the above helper function. On the other hand, you might want to add some protection against the infinite recursion that would occur if printLevelNodes is called with a negative value of k:
void MovieTree::printLevelNodes(int k) {
if (k >= 0) printLevelNodesHelper(root, k);
}

Stuck/general help in developing A* on a 2D grid

I think I am close to finishing this implementation of A* but my mind is becoming fried and am looking for pointers on what I should be doing to complete it.
My current problem is that my function that runs through A* remains stuck on the same node, as in the current node never moves into any other of the open nodes.
Here is my main function, note that the heuristic(Node &n1, Node &n2) function is currently set to always to return 0, so it should currently be working more like a Dijkstra algorithm rather than A*. Also, movement is restricted to the NESW plane, no diagonal movement, so distance_between(Node &n1, Node &n2) always returns 1.
void astar(Node start_, Node end_) {
Node start = start_;
Node end = end_;
// compute f,g,h for the start node
start.g = 0;
start.h = heuristic(start, end);
start.f = start.g + start.h;
// insert start node into the open set
openNodes.insert(&start);
// while the set of open nodes is not empty
while (openNodes.size() > 0) {
// pick the most promising node to look at next
Node currentNode;
cout << "currentNode before: ";
currentNode.displaylocation();
// go through all the open nodes and find the one with the smallest 'f' value
Node* minf = (*openNodes.begin()); // set initial value for minimum f to be the first node in the set of open nodes
for (auto n : openNodes) {
if (n->f <= minf->f) {
minf = n;
}
}
currentNode = *minf; // set the current node to the node that holds the smallest 'f' value
cout << "currentNode after: ";
currentNode.displaylocation();
// if the current node is the end node, then we have found a path
if (currentNode.type == -3) {
break;
}
// remove the current node from the set of open nodes, and add it to the set of closed nodes
openNodes.erase(&currentNode);
closedNodes.insert(&currentNode);
// go through the currents node's neighbours
for (auto n : neighbours(currentNode)) {
cout << "neighbour local: " << n.location.x << "," << n.location.y << "\n";
if (closedNodes.count(&n) == 0 && n.type != -2) { // if this node is neither closed or a blocker
int new_g = currentNode.g + distance_between(currentNode, n);
if (openNodes.count(&n) != 0) { // if we have not seen this node before, add to the open set
openNodes.insert(&n);
}
else if (new_g >= n.g) { // else if we have seen this node before, and already found a shorter path to it from the starting node
}
n.g = new_g;
n.f = n.g + heuristic(n, end);
n.parent_ = &currentNode;
}
}
cout << "\n A* run success! \n";
//break;
}
}
Here is the deceleration of things like the Node struct and the global variables:
// The size of the grid
#define WIDTH 6
#define HEIGHT 6
// Holds values for x and y locations on the grid
struct Coord {
int x, y;
};
// holds data for each node required for A*
struct Node {
int type; // used for defining if this node is a blocker, empty, start or end
Coord location;
int g = 0;
int h = 0;
int f = g + h;
Node *parent_; // pointer to this node's parent
std::string debugmessage;
void displaylocation() {
std::cout << "I am the node at: " << location.x << "," << location.y << "\n";
}
};
// The 2D grid array for A*, requiring a Node struct to store the data of each cell
Node astarArray[WIDTH][HEIGHT];
// Sets for A*
std::set<Node *> openNodes; // contains the nodes that are yet to be considered (if this is empty, then there are no more paths to consider or there is no path)
std::set<Node *> closedNodes; // contains the nodes that have already been considered (if the end node is placed in here, a path has been found)
// stores the start and end values for A*
Node start_A, end_A;
void astar(Node start_, Node end_);
int distance_between(Node& n1, Node& n2);
int heuristic(Node& n1, Node& n2);
std::list<Node> neighbours(Node& n_);
// returns the distance between two nodes for A*
int distance_between(Node& n1, Node& n2) {
return 1; // always return 1 as we are working in a grid restricted to NSEW movement
}
int heuristic(Node& n1, Node& n2) {
return 0; // return 0 to work as a Dijkstra algorithm rather than A*
}
// finds a node's neighbours for A*
std::list<Node> neighbours(Node& n_) {
std::list<Node> neighbours_;
int x = n_.location.x;
int y = n_.location.y;
// start at the location belonging to 'n_'
//for (int y = n_.location.y; y < HEIGHT; y++) {
//for (int x = n_.location.x; x < WIDTH; x++) {
// east
if (x < WIDTH - 1) {
neighbours_.push_back(astarArray[x + 1][y]);
}
// west
if (x > 0) {
neighbours_.push_back(astarArray[x - 1][y]);
}
// south
if (y < HEIGHT - 1) {
neighbours_.push_back(astarArray[x][y + 1]);
}
// north
if (y > 0) {
neighbours_.push_back(astarArray[x][y -1]);
}
//}
//}
return neighbours_;
}
Thank you very much for reading and for any help you can give. I will provide more code if required.
The main problem you have is that you are using the pointers (mem address) to find out if a node is in your set or not.
currentNode = *minf; // set the current node to the node that holds the smallest 'f' value
Then you copy to currentNode the contents of minf.
currentNode will have a different address from the pointer to minf
openNodes.erase(&currentNode); will not remove minf because currentNode does not have the same address.
I would suggest you investigate more on how to implement A* as you are missing some steps. Look for priority queues.
Instead of the mem address of the node, use the position index for that node in the grid (pos.x * numCols) + pos.y

List and count the most weight path from the root to the leafs of a binary tree

I have to return the number of nodes and the weight of the most weight path from the root to some leaf. Note that the tree is not a Binary Search Tree, is unsorted.
i.e.:
6
/ \
9 6
/ / \
3 1 19
Then, I have to return the integer 6 + 6 + 19 = 31 and print the node 6 - 6 - 19
So, this is my code:
int heavierPath ( Node * tree ) {
if ( ! tree ) return 0;
int leftWeight = heavierPath( tree->left );
int rightWeight= heavierPath( tree->right );
if ( leftWeight >= rightWeight ) {
if ( tree->left )
cout << tree->left->value << endl;
return tree->value + leftWeight;
}
else {
cout << tree->right->value << endl;
return tree->value + rightWeight;
}
};
And the result is 31, but I see all the nodes values in the terminal.
How can I do to fix it and print only the elements that lies in the heavier path? (only recursive)
Thanks!
This appears to work after I edited it.
Take a look at: http://ideone.com/OGcyun as an example.
Your problem:
Consider the graph as:
6
/ \
9 6
/ / \
3 1 19
Number each node so:
0
/ \
1 2
/ / \
3 4 5
Consider the case where you are at node 1.
You ask for the better path which gives you leftWeight = 3 and rightweight = 0 and you print the "better" path, 3. which isn't part of the end result.
The solution
To solve this problem, I passed up additional data up in a retstruct which contain the path (the heaviest path up to this point), value (to make printing easier), sum (to determine the better path).
Then I changed the function to:
retstruct* heavierPath ( Node * tree ) {
if ( ! tree ) return new retstruct();
//Get both paths
retstruct* leftWeight = heavierPath( tree->left );
retstruct* rightWeight= heavierPath( tree->right );
//Find the "heavier" path
if ( leftWeight->sum >= rightWeight->sum ) {
//Delete lighter path
delete_retstruct(rightWeight);
//Pass up the better path with the correct data
return new retstruct(leftWeight, tree->value, tree->value + leftWeight->sum);
} else {
//Delete lighter path
delete_retstruct(leftWeight);
//Pass up the better path with the correct data
return new retstruct(rightWeight, tree->value, tree->value + rightWeight->sum);
}
};
Added the delete_retstruct function:
void delete_retstruct (retstruct* path) {
if (path->path == NULL) {
delete path;
} else {
delete_retstruct(path->path);
}
}
and the printPath function:
void printPath (retstruct* path) {
if (path->path != NULL) {
std::cout << " - " << path->value;
printPath(path->path);
}
}
This is used like so:
retstruct* path = heavierPath(tree);
//Print sum
std::cout << "Sum: " << path->sum << std::endl;
//Print path
std::cout << "Path: " << path->value;
printPath(path->path);
std::cout << std::endl;
Output:
Sum: 31
Path: 6 - 6 - 19
My suggestion is to make two functions,first function will find the leaf where path from root to it is maximum. So assuming you have pointer to such leaf here is the function to print the path.
bool print(struct node *r, struct node *leaf)
{
if (r == NULL)
return false;
//will print if it is leaf or on path to leaf
if (r == leaf || print(r->left, leaf) || print(r->right, leaf) )
{
printf("%d ", r->val); // this will print in reverse order
// if you want to print from root, store values in stack and then print the value after the function call
return true;
}
return false;
}
The problem is that you are mixing printing the node with finding the sum. The later has to visit all child-nodes while printing only has to visit the ones in the path.
Below is a possible solution:
#include <iostream>
#include <unordered_map>
struct Node
{
Node(int value = 0, Node* left = nullptr, Node* right = nullptr) :
value{value},
left{left},
right{right}
{}
int value;
Node* left;
Node* right;
};
std::unordered_map<Node*, int> map;
int pathSum(Node* node)
{
if (node == nullptr)
{
return 0;
}
else if (map.find(node) == map.end())
{
return (pathSum(node->left) > pathSum(node->right))
? (map[node] = node->value + pathSum(node->left))
: (map[node] = node->value + pathSum(node->right));
}
else
{
return map[node];
}
}
void printPath(Node* node)
{
if (node == nullptr)
{
return;
}
std::cout << node->value << std::endl;
if (pathSum(node->left) > pathSum(node->right))
{
printPath(node->left);
}
else
{
printPath(node->right);
}
}
int main() {
Node* tree = new Node(6,
new Node(9,
new Node(3)),
new Node(6,
new Node(1),
new Node(19)));
std::cout << "Biggest Sum: " << pathSum(tree) << std::endl;
std::cout << "Biggest Sum Path: " << std::endl;
printPath(tree);
return 0;
}
In recursive solutions such as this, it's a good idea to cache the results hence the std::unordered_map. The code has been tested at Ideone.