Consider the following AVL-tree implementation. Each node contains a list of numbers.The key is named workload, but consider it as a plain double variable. If a key is equal to the key of an already existing node, the number gets pushed into the list. Every time I pop a number from a list, I perform a check, if the node's list is empty -> remove the node. But, after the element with key=3 gets removed completely, the list of the node with key=4 is suddenly empty. I've been trying to solve it for over 10 hours now, it's actually the first time I ever needed to ask something here. Pardon me if I miss a few things.
#include<iostream>
#include <list>
using namespace std;
class BST
{
struct node
{
double workload;
list<int> numbers;
node* left;
node* right;
int height;
};
node* root;
unsigned long long size;
bool empty;
void makeEmpty(node* t)
{
if(t == NULL)
return;
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
node* insert(double workload,int number, node* t)
{
if(t == NULL)
{
t = new node;
t->workload = workload;
t->numbers.push_back(number);
t->height = 0;
t->left = t->right = NULL;
}
else if(t->workload == workload){
t->numbers.push_back(number);
}
else if(workload < t->workload)
{
t->left = insert(workload, number, t->left);
if(height(t->left) - height(t->right) == 2)
{
if(workload < t->left->workload)
t = singleRightRotate(t);
else
t = doubleRightRotate(t);
}
}
else if(workload > t->workload)
{
t->right = insert(workload, number, t->right);
if(height(t->right) - height(t->left) == 2)
{
if(workload > t->right->workload)
t = singleLeftRotate(t);
else
t = doubleLeftRotate(t);
}
}
//if x == t->workload instead of using int workload. its a list and we push into it.
t->height = max(height(t->left), height(t->right))+1;
return t;
}
node* singleRightRotate(node* &t)
{
node* u = t->left;
t->left = u->right;
u->right = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(u->left), t->height)+1;
return u;
}
node* singleLeftRotate(node* &t)
{
node* u = t->right;
t->right = u->left;
u->left = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(t->right), t->height)+1 ;
return u;
}
node* doubleLeftRotate(node* &t)
{
t->right = singleRightRotate(t->right);
return singleLeftRotate(t);
}
node* doubleRightRotate(node* &t)
{
t->left = singleLeftRotate(t->left);
return singleRightRotate(t);
}
node* findMin(node* t)
{
if(t == NULL)
return NULL;
else if(t->left == NULL)
return t;
else
return findMin(t->left);
}
node* findMax(node* t)
{
if(t == NULL)
return NULL;
else if(t->right == NULL)
return t;
else
return findMax(t->right);
}
node* find(node* t,double workload){
if (t->workload == workload){
return t;
}
else if(workload < t->workload && t->left!=NULL)
return find(t->left,workload);
else if(workload > t->workload && t->right!=NULL)
return find(t->right,workload);
else{
cout << "Null node encountered" << endl;
return t;
}
}
node* remove(double x, node* t)
{
node* temp;
// Element not found
if(t == NULL)
return NULL;
// Searching for element
if(x < t->workload)
t->left = remove(x, t->left);
else if(x > t->workload)
t->right = remove(x, t->right);
// Element found
// With 2 children
else if(t->left && t->right)
{
temp = findMin(t->right);
t->workload = temp->workload;
t->right = remove(t->workload, t->right);
}
// With one or zero child
else
{
temp = t;
if(t->left == NULL)
t = t->right;
else if(t->right == NULL)
t = t->left;
delete temp;
}
if(t == NULL)
return t;
t->height = max(height(t->left), height(t->right))+1;
// If node is unbalanced
// If left node is deleted, right case
if(height(t->left) - height(t->right) == -2)
{
// right right case
if(height(t->right->right) - height(t->right->left) == 1)
return singleLeftRotate(t);
// right left case
else
return doubleLeftRotate(t);
}
// If right node is deleted, left case
else if(height(t->right) - height(t->left) == 2)
{
// left left case
if(height(t->left->left) - height(t->left->right) == 1){
return singleRightRotate(t);
}
// left right case
else
return doubleRightRotate(t);
}
return t;
}
int height(node* t)
{
return (t == NULL ? -1 : t->height);
}
int getBalance(node* t)
{
if(t == NULL)
return 0;
else
return height(t->left) - height(t->right);
}
void inorder(node* t)
{
if(t == NULL)
return;
inorder(t->left);
cout << t->workload<< " ";
inorder(t->right);
}
//Reverse inorder (Sorted highest to lowest)
void rinorder(node* t)
{
if(t == NULL)
return;
rinorder(t->right);
cout << t->workload << " ";
rinorder(t->left);
}
void preorder(node* t)
{
if (t == NULL)
return;
cout << t->workload << " ";
preorder(t->left);
preorder(t->right);
}
void postorder(node* t)
{
if (t == NULL)
return;
postorder(t->left);
postorder(t->right);
cout << t->workload << " ";
}
public:
BST()
{
root = NULL;
}
void insert(double workload, int number)
{
root = insert(workload, number, root);
}
void remove(double workload)
{
root = remove(workload, root);
}
void displayrin()
{
cout << "Rinorder: ";
rinorder(root);
cout << endl;
}
void displayin()
{
cout << "Inorder: ";
inorder(root);
cout << endl;
}
void displaypost()
{
cout << "Postorder: ";
postorder(root);
cout << endl;
}
void displaypre()
{
cout << "Preorder: ";
preorder(root);
cout << endl;
}
double getMax(){
return findMax(root)->workload;
}
int getMaxNum(){
return find(root,getMax())->numbers.front();
}
int getNum(double workload){
return find(root,workload)->numbers.front();
}
//We pop a Num from a node
void popnumber(double workload){
node *t = find(root,workload);
if(t!=NULL){
if(!t->numbers.empty()){
t->numbers.pop_front();
//If the Num list of the node is empty, remove node
if(t->numbers.empty()){
remove(t->workload);
}
}
}
}
};
int main()
{
BST t;
//key value pairs
t.insert(2,1);
t.insert(3,1);
t.insert(3,2);
t.insert(4,7);
cout << t.getNum(4) << endl;
cout << t.getNum(3)<<endl;
t.popnumber(3);
cout << t.getNum(3)<<endl;
t.popnumber(3);
t.displayin();
t.displaypost();
t.displaypre();
t.displayrin();
cout << t.getNum(4) << endl;
cout << "The max is : " << t.getMax() << endl;
cout << "The top Num of the Max is : " << t.getMaxNum() << endl;
return 0;
}
As mentioned in the comments, the problem is in the "Element found With 2 children" section of remove.
To remove the element, you find the next element in the tree. Your implementation then wants to copy the contents of the found node (temp). You copy the workload value, so that both t and temp have the same workload value (4). You do not copy the numbers list. The t node has a workload of 4 and an empty numbers list, while temp has a workload of 4 and a numbers list consisting of one element, 7. You then delete temp, losing the list.
One fix would be to copy (or move) numbers from temp to t before removing it from the tree. Adding a MoveData method to node that would move the data fields (while not altering the tree specific fields) would make it easier to add new data fields.
Another fix would be to change how you're doing the data update. If you update all pointers (and other tree related fields like height), then you don't have to worry about the data (and any pointers/iterators to the nodes would not be invalidated).
I'm working on an AVL Tree sorting algorithm, and I thought I finally had it figured out, thanks to the help of you all, until I realized that the runtime for it was taking significantly longer than the runtime for insertion sort, which shouldn't be correct. I'm using an unsorted array (or rather, vector) of randomly generated numbers. I'll provide some statistics and code below.
AVL
for (std::vector<int>::const_iterator i = numbers.begin(); i != numbers.begin()+30000; ++i)
{
root = insert(root, numbers[x]);
cout << "Height: " << height(root);
x++;
track++;
if( (track % 10000) == 0)
{
cout << track << " iterations" << endl;
time_t now = time(0);
cout << now - begin << " seconds" << endl;
}
}
N = 30,000
Height = 17
Number of iterations performed = ~1,730,000
Run time for sorting = 38 seconds
Insertion Sort
for (int i = 0; i < 30000; i++)
{
first++;
cout << first << " first level iterations" << endl;
time_t now = time(0);
cout << now - begin << " seconds" << endl;
int tmp = dataSet[i];
int j;
for (j = i; i > 0 && tmp < dataSet[j - 1]; j--)
{
dataSet[j] = dataSet[j - 1];
}
dataSet[j] = tmp;
}
}
N = 30,000
Iterations = 30,000
Run time for sorting = 4 seconds
This can't possibly be right, so I was hoping that maybe you all could help figure out what's going on? As far as I can tell, all of my code was implemented correctly, but I'm still going to include the relevant parts below in case I missed something.
Source Code
node* newNode(int element) // helper function to return a new node with empty subtrees
{
node* newPtr = new node;
newPtr->data = element;
newPtr->leftChild = NULL;
newPtr->rightChild = NULL;
newPtr->height = 1;
return newPtr;
}
node* rightRotate(node* p) // function to right rotate a tree rooted at p
{
node* child = p->leftChild;
node* grandChild = child->rightChild;
// perform the rotation
child->rightChild = p;
p->leftChild = grandChild;
// update the height for the nodes
p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
child->height = max(height(child->leftChild), height(child->rightChild)) + 1;
// return new root
return child;
}
node* leftRotate(node* p) // function to left rotate a tree rooted at p
{
node* child = p->rightChild;
node* grandChild = child->leftChild;
// perform the rotation
child->leftChild = p;
p->rightChild = grandChild;
// update heights
p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
// return new root
return child;
}
int getBalance(node *p)
{
if(p == NULL)
return 0;
else
return height(p->leftChild) - height(p->rightChild);
}
// recursive version of BST insert to insert the element in a sub tree rooted with root
// which returns new root of subtree
node* insert(node*& n, int element)
{
// perform the normal BST insertion
if(n == NULL) // if the tree is empty
return(newNode(element));
if(element< n->data)
{
n->leftChild = insert(n->leftChild, element);
}
else
{
n->rightChild = insert(n->rightChild, element);
}
// update the height for this node
n->height = 1 + max(height(n->leftChild), height(n->rightChild));
// get the balance factor to see if the tree is unbalanced
int balance = getBalance(n);
// the tree is unbalanced, there are 4 different types of rotation to make
// Single Right Rotation (Left Left Case)
if(balance > 1 && element < n->leftChild->data)
{
return rightRotate(n);
}
// Single Left Rotation (Right Right Case)
if(balance < -1 && element > n->rightChild->data)
{
return leftRotate(n);
}
// Left Right Rotation
if(balance > 1 && element > n->leftChild->data)
{
n->leftChild = leftRotate(n->leftChild);
return rightRotate(n);
}
// Right Left Rotation
if(balance < -1 && element < n->rightChild->data)
{
n->rightChild = rightRotate(n->rightChild);
return leftRotate(n);
}
// cout << "Height: " << n->height << endl;
// return the unmodified root pointer in the case that the tree does not become unbalanced
return n;
}
The best way to "debug" this kind of problems is to use a performance profiler tool, however in this case I think I can give you a good hypothesis:
Insertion sort is an "in place" algorithm, no memory allocations are required.
Your AVL tree requires many memory allocations, and these are expensive
In summary, your comparison is not "fair".
How to "fix" this?:
Experiment with memory management libraries, like Boost.Pool.
As an example, if you know in advance how many nodes your tree will have, you can allocate all the required nodes at once at the beginning of your algorithm, and create a pool of nodes with them (if you use Boost this should be a lot faster than calling the standard new operator every time, one by one).
Every time you need a new node, you take it from the pool. You can then "compare" the algorithms from the point where no additional memory allocations will be required.
I am working on writing a list of children binary tree implementation. In my code I have an array of lists. Each list contains a node followed by its children on the tree. I finished writing the code and everything compiled, but I keep getting a segmentation fault error and I cannot figure out why. I have been attempting to debug and figure out where my code messes up. I know that there is an issue with the FIRST function. It causes a segmentation fault. Also, when I try to print just one of the lists of the array, it prints everything. I have been stuck on this for a very long time now and would like some help. Can anyone offer suggestions as to why the FIRST and PRINT functions are not working? Maybe there is a large error that I just cannot see.
My code is as follows:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <array>
#include <string.h>
using namespace std;
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
void ADD(char n);
node* CREATE(char n);
void BEGIN(char n);
char FIRST();
char END();
char NEXT(char n);
char PREVIOUS(char n);
int LOCATE(char n);
void EMPTY();
void PRINT();
list()
{
start = NULL;
}
};
char PARENT(const char n, list tree[], int length)
{
int i=0;
list l;
for (i; i<length; i++)
{
l = tree[i];
if (n != l.FIRST())
{
if (l.LOCATE(n)>0)
return l.FIRST();
}
}
}
char LEFTMOST_CHILD(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if (l.FIRST() == n)
return l.NEXT(n);
}
}
char RIGHT_SIBLING(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if(n != l.FIRST())
{
if (l.LOCATE(n) > 0)
{
return l.NEXT(n);
}
}
}
}
char ROOT(list tree[]) //assumes array is in order, root is first item
{
list l;
l = tree[0];
cout << "Assigned tree to l" << endl;
return l.FIRST();
}
void MAKENULL(list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
l.EMPTY();
}
}
void list::PRINT()
{
struct node *temp;
if (start == NULL)
{
cout << "The list is empty" << endl;
return;
}
temp = start;
cout << "The list is: " << endl;
while (temp != NULL)
{
cout << temp->element << "->" ;
temp = temp->next;
}
cout << "NULL" << endl << endl;
}
void list::EMPTY()
{
struct node *s, *n;
s = start;
while (s != NULL)
{
n = s->next;
free(s);
s = n;
}
start = NULL;
}
int list::LOCATE(char n)
{
int pos = 0;
bool flag = false;
struct node *s;
s = start;
while (s != NULL)
{
pos++;
if (s->element == n)
{
flag == true;
return pos;
}
s = s->next;
}
if (!flag)
return -1;
}
void list::ADD(char n)
{
struct node *temp, *s;
temp = CREATE(n);
s = start;
while (s->next != NULL)
s = s->next;
temp->next = NULL;
s->next = temp;
}
node *list::CREATE(char n)
{
struct node *temp;
temp = new(struct node);
temp->element = n;
temp->next = NULL;
return temp;
}
void list::BEGIN(char n)
{
struct node *temp, *p;
temp = CREATE(n);
if (start == NULL)
{
start = temp;
start->next = NULL;
}
}
char list::FIRST()
{
char n;
struct node *s;
s = start;
cout << "s = start" << endl;
n = s->element;
cout << "n" << endl;
return n;
}
char list::END()
{
struct node *s;
s = start;
int n;
while (s != NULL)
{
n = s->element;
s = s->next;
}
return n;
}
char list::NEXT(char n)
{
char next;
struct node *s;
s = start;
while (s != NULL)
{
if (s->element == n)
break;
s = s->next;
}
s = s->next;
next = s->element;
return next;
}
char list::PREVIOUS(char n)
{
char previous;
struct node *s;
s = start;
while (s != NULL)
{
previous = s->element;
s = s->next;
if (s->element == n)
break;
}
return previous;
}
main()
{
list a,b,c,d,e,f,g,h,i,j,k,l,m,n;
a.BEGIN('A');
b.BEGIN('B');
c.BEGIN('C');
d.BEGIN('D');
e.BEGIN('E');
f.BEGIN('F');
g.BEGIN('G');
h.BEGIN('H');
i.BEGIN('I');
j.BEGIN('J');
k.BEGIN('K');
l.BEGIN('L');
m.BEGIN('M');
n.BEGIN('N');
a.ADD('B');
a.ADD('C');
b.ADD('D');
b.ADD('E');
e.ADD('I');
i.ADD('M');
i.ADD('N');
c.ADD('F');
c.ADD('G');
c.ADD('H');
g.ADD('J');
g.ADD('K');
h.ADD('L');
a.PRINT();
list tree[] = {a,b,c,d,e,f,g,h,i,j,k,l,m,n};
int length = sizeof(tree)/sizeof(char);
char root = ROOT(tree);
cout << "Found root" << endl;
char parent = PARENT('G', tree, length);
cout << "Found Parent" << endl;
char leftChild = LEFTMOST_CHILD('C', tree, length);
cout << "found left child" << endl;
char rightSibling = RIGHT_SIBLING('D', tree, length);
cout << "found right sibling" << endl;
cout << "The root of the tree is: ";
cout << root << endl;
cout << "The parent of G is: ";
cout << parent << endl;
cout << "The leftmost child of C is" ;
cout << leftChild << endl;
cout << "The right sibling of D is: " ;
cout << rightSibling << endl;
}
Any help will be very appreciated. Thanks you!
The fundamental problem is that you have written a lot of code before testing any of it. When you write code, start with something small and simple that works perfectly, add complexity a little at a time, test at every step, and never add to code that doesn't work.
The specific problem (or at least one fatal problem) is here:
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
//...
list()
{
start = NULL;
}
};
The variable start is a global variable. The class list has no member variables, but uses the global variable. It sets start to NULL every time a list is constructed, and every list messes with the same pointer. The function FIRST dereferences a pointer without checking whether the pointer is NULL, and when it is, you get Undefined Behavior.
It's not entirely clear what you intended, but you seem to misunderstand how variables work in C++.
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
2
Right now what it prints is:
2
4
3
6
7
11
10
5
I know that my example is upside down from what I'm currently printing, which it doesn't matter if I print from the root down as it currently prints. Any tips are very appreciated towards my full question:
How do I modify my prints to make the tree look like a tree?
//Binary Search Tree Program
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
int i = 0;
class BinarySearchTree
{
private:
struct tree_node
{
tree_node* left;
tree_node* right;
int data;
};
tree_node* root;
public:
BinarySearchTree()
{
root = NULL;
}
bool isEmpty() const { return root==NULL; }
void print_inorder();
void inorder(tree_node*);
void print_preorder();
void preorder(tree_node*);
void print_postorder();
void postorder(tree_node*);
void insert(int);
void remove(int);
};
// Smaller elements go left
// larger elements go right
void BinarySearchTree::insert(int d)
{
tree_node* t = new tree_node;
tree_node* parent;
t->data = d;
t->left = NULL;
t->right = NULL;
parent = NULL;
// is this a new tree?
if(isEmpty()) root = t;
else
{
//Note: ALL insertions are as leaf nodes
tree_node* curr;
curr = root;
// Find the Node's parent
while(curr)
{
parent = curr;
if(t->data > curr->data) curr = curr->right;
else curr = curr->left;
}
if(t->data < parent->data)
{
parent->left = t;
}
else
{
parent->right = t;
}
}
}
void BinarySearchTree::remove(int d)
{
//Locate the element
bool found = false;
if(isEmpty())
{
cout<<" This Tree is empty! "<<endl;
return;
}
tree_node* curr;
tree_node* parent;
curr = root;
while(curr != NULL)
{
if(curr->data == d)
{
found = true;
break;
}
else
{
parent = curr;
if(d>curr->data) curr = curr->right;
else curr = curr->left;
}
}
if(!found)
{
cout<<" Data not found! "<<endl;
return;
}
// 3 cases :
// 1. We're removing a leaf node
// 2. We're removing a node with a single child
// 3. we're removing a node with 2 children
// Node with single child
if((curr->left == NULL && curr->right != NULL) || (curr->left != NULL && curr->right == NULL))
{
if(curr->left == NULL && curr->right != NULL)
{
if(parent->left == curr)
{
parent->left = curr->right;
delete curr;
}
else
{
parent->right = curr->left;
delete curr;
}
}
return;
}
//We're looking at a leaf node
if( curr->left == NULL && curr->right == NULL)
{
if(parent->left == curr)
{
parent->left = NULL;
}
else
{
parent->right = NULL;
}
delete curr;
return;
}
//Node with 2 children
// replace node with smallest value in right subtree
if (curr->left != NULL && curr->right != NULL)
{
tree_node* chkr;
chkr = curr->right;
if((chkr->left == NULL) && (chkr->right == NULL))
{
curr = chkr;
delete chkr;
curr->right = NULL;
}
else // right child has children
{
//if the node's right child has a left child
// Move all the way down left to locate smallest element
if((curr->right)->left != NULL)
{
tree_node* lcurr;
tree_node* lcurrp;
lcurrp = curr->right;
lcurr = (curr->right)->left;
while(lcurr->left != NULL)
{
lcurrp = lcurr;
lcurr = lcurr->left;
}
curr->data = lcurr->data;
delete lcurr;
lcurrp->left = NULL;
}
else
{
tree_node* tmp;
tmp = curr->right;
curr->data = tmp->data;
curr->right = tmp->right;
delete tmp;
}
}
return;
}
}
void BinarySearchTree::print_postorder()
{
postorder(root);
}
void BinarySearchTree::postorder(tree_node* p)
{
if(p != NULL)
{
if(p->left) postorder(p->left);
if(p->right) postorder(p->right);
cout<<" "<<p->data<<"\n ";
}
else return;
}
int main()
{
BinarySearchTree b;
int ch,tmp,tmp1;
while(1)
{
cout<<endl<<endl;
cout<<" Binary Search Tree Operations "<<endl;
cout<<" ----------------------------- "<<endl;
cout<<" 1. Insertion/Creation "<<endl;
cout<<" 2. Printing "<<endl;
cout<<" 3. Removal "<<endl;
cout<<" 4. Exit "<<endl;
cout<<" Enter your choice : ";
cin>>ch;
switch(ch)
{
case 1 : cout<<" Enter Number to be inserted : ";
cin>>tmp;
b.insert(tmp);
i++;
break;
case 2 : cout<<endl;
cout<<" Printing "<<endl;
cout<<" --------------------"<<endl;
b.print_postorder();
break;
case 3 : cout<<" Enter data to be deleted : ";
cin>>tmp1;
b.remove(tmp1);
break;
case 4:
return 0;
}
}
}
In order to pretty-print a tree recursively, you need to pass two arguments to your printing function:
The tree node to be printed, and
The indentation level
For example, you can do this:
void BinarySearchTree::postorder(tree_node* p, int indent=0)
{
if(p != NULL) {
if(p->left) postorder(p->left, indent+4);
if(p->right) postorder(p->right, indent+4);
if (indent) {
std::cout << std::setw(indent) << ' ';
}
cout<< p->data << "\n ";
}
}
The initial call should be postorder(root);
If you would like to print the tree with the root at the top, move cout to the top of the if.
void btree::postorder(node* p, int indent)
{
if(p != NULL) {
if(p->right) {
postorder(p->right, indent+4);
}
if (indent) {
std::cout << std::setw(indent) << ' ';
}
if (p->right) std::cout<<" /\n" << std::setw(indent) << ' ';
std::cout<< p->key_value << "\n ";
if(p->left) {
std::cout << std::setw(indent) << ' ' <<" \\\n";
postorder(p->left, indent+4);
}
}
}
With this tree:
btree *mytree = new btree();
mytree->insert(2);
mytree->insert(1);
mytree->insert(3);
mytree->insert(7);
mytree->insert(10);
mytree->insert(2);
mytree->insert(5);
mytree->insert(8);
mytree->insert(6);
mytree->insert(4);
mytree->postorder(mytree->root);
Would lead to this result:
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.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
struct Node *left,*right;
int val;
} *root=NULL;
int rec[1000006];
void addNode(int,struct Node*);
void printTree(struct Node* curr,int depth)
{
int i;
if(curr==NULL)return;
printf("\t");
for(i=0;i<depth;i++)
if(i==depth-1)
printf("%s\u2014\u2014\u2014",rec[depth-1]?"\u0371":"\u221F");
else
printf("%s ",rec[i]?"\u23B8":" ");
printf("%d\n",curr->val);
rec[depth]=1;
printTree(curr->left,depth+1);
rec[depth]=0;
printTree(curr->right,depth+1);
}
int main()
{
root=(struct Node*)malloc(sizeof(struct Node));
root->val=50;
//addNode(50,root);
addNode(75,root); addNode(25,root);
addNode(15,root); addNode(30,root);
addNode(100,root); addNode(60,root);
addNode(27,root); addNode(31,root);
addNode(101,root); addNode(99,root);
addNode(5,root); addNode(61,root);
addNode(55,root); addNode(20,root);
addNode(0,root); addNode(21,root);
//deleteNode(5,root);
printTree(root,0);
return 0;
}
void addNode(int v,struct Node* traveller)
{
struct Node *newEle=(struct Node*)malloc(sizeof(struct Node));
newEle->val=v;
for(;;)
{
if(v<traveller->val)
{
if(traveller->left==NULL){traveller->left=newEle;return;}
traveller=traveller->left;
}
else if(v>traveller->val)
{
if(traveller->right==NULL){traveller->right=newEle;return;}
traveller=traveller->right;
}
else
{
printf("%d Input Value is already present in the Tree !!!\n",v);
return;
}
}
}
Hope, you find it pretty...
Output:
50
ͱ———25
⎸ ͱ———15
⎸ ⎸ ͱ———5
⎸ ⎸ ⎸ ͱ———0
⎸ ⎸ ∟———20
⎸ ⎸ ∟———21
⎸ ∟———30
⎸ ͱ———27
⎸ ∟———31
∟———75
ͱ———60
⎸ ͱ———55
⎸ ∟———61
∟———100
ͱ———99
∟———101
//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));
}
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
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 + " ");
}
}
Here's a little example for printing out an array based heap in tree form. It would need a little adjusting to the algorithm for bigger numbers. I just made a grid on paper and figured out what space index each node would be to look nice, then noticed there was a pattern to how many spaces each node needed based on its parent's number of spaces and the level of recursion as well as how tall the tree is. This solution goes a bit beyond just printing in level order and satisfies the "beauty" requirement.
#include <iostream>
#include <vector>
static const int g_TerminationNodeValue = -999;
class HeapJ
{
public:
HeapJ(int* pHeapArray, int numElements)
{
m_pHeapPointer = pHeapArray;
m_numElements = numElements;
m_treeHeight = GetTreeHeight(1);
}
void Print()
{
m_printVec.clear();
int initialIndex = 0;
for(int i=1; i<m_treeHeight; ++i)
{
int powerOfTwo = 1;
for(int j=0; j<i; ++j)
{
powerOfTwo *= 2;
}
initialIndex += powerOfTwo - (i-1);
}
DoPrintHeap(1,0,initialIndex);
for(size_t i=0; i<m_printVec.size(); ++i)
{
std::cout << m_printVec[i] << '\n' << '\n';
}
}
private:
int* m_pHeapPointer;
int m_numElements;
int m_treeHeight;
std::vector<std::string> m_printVec;
int GetTreeHeight(int index)
{
const int value = m_pHeapPointer[index-1];
if(value == g_TerminationNodeValue)
{
return -1;
}
const int childIndexLeft = 2*index;
const int childIndexRight = childIndexLeft+1;
int valLeft = 0;
int valRight = 0;
if(childIndexLeft <= m_numElements)
{
valLeft = GetTreeHeight(childIndexLeft);
}
if(childIndexRight <= m_numElements)
{
valRight = GetTreeHeight(childIndexRight);
}
return std::max(valLeft,valRight)+1;
}
void DoPrintHeap(int index, size_t recursionLevel, int numIndents)
{
const int value = m_pHeapPointer[index-1];
if(value == g_TerminationNodeValue)
{
return;
}
if(m_printVec.size() == recursionLevel)
{
m_printVec.push_back(std::string(""));
}
const int numLoops = numIndents - (int)m_printVec[recursionLevel].size();
for(int i=0; i<numLoops; ++i)
{
m_printVec[recursionLevel].append(" ");
}
m_printVec[recursionLevel].append(std::to_string(value));
const int childIndexLeft = 2*index;
const int childIndexRight = childIndexLeft+1;
const int exponent = m_treeHeight-(recursionLevel+1);
int twoToPower = 1;
for(int i=0; i<exponent; ++i)
{
twoToPower *= 2;
}
const int recursionAdjust = twoToPower-(exponent-1);
if(childIndexLeft <= m_numElements)
{
DoPrintHeap(childIndexLeft, recursionLevel+1, numIndents-recursionAdjust);
}
if(childIndexRight <= m_numElements)
{
DoPrintHeap(childIndexRight, recursionLevel+1, numIndents+recursionAdjust);
}
}
};
const int g_heapArraySample_Size = 14;
int g_heapArraySample[g_heapArraySample_Size] = {16,14,10,8,7,9,3,2,4,1,g_TerminationNodeValue,g_TerminationNodeValue,g_TerminationNodeValue,0};
int main()
{
HeapJ myHeap(g_heapArraySample,g_heapArraySample_Size);
myHeap.Print();
return 0;
}
/* output looks like this:
16
14 10
8 7 9 3
2 4 1 0
*/
Foreword
Late late answer and its in Java, but I'd like to add mine to the record because I found out how to do this relatively easily and the way I did it is more important. The trick is to recognize that what you really want is for none of your sub-trees to be printed directly under your root/subroot nodes (in the same column). Why you might ask? Because it Guarentees that there are no spacing problems, no overlap, no possibility of the left subtree and right subtree ever colliding, even with superlong numbers. It auto adjusts to the size of your node data. The basic idea is to have the left subtree be printed totally to the left of your root and your right subtree is printed totally to the right of your root.
An anaology of how I though about this problem
A good way to think about it is with Umbrellas, Imagine first that you are outside with a large umbrella, you represent the root and your Umbrella and everything under it is the whole tree. think of your left subtree as a short man (shorter than you anyway) with a smaller umbrella who is on your left under your large umbrella. Your right subtree is represented by a similar man with a similarly smaller umbrella on your right side. Imagine that if the umbrellas of the short men ever touch, they get angry and hit each other (bad overlap). You are the root and the men beside you are your subtrees. You must be exactly in the middle of their umbrellas (subtrees) to break up the two men and ensure they never bump umbrellas. The trick is to then imagine this recursively, where each of the two men each have their own two smaller people under their umbrella (children nodes) with ever smaller umbrellas (sub-subtrees and so-on) that they need to keep apart under their umbrella (subtree), They act as sub-roots. Fundamentally, thats what needs to happen to 'solve' the general problem when printing binary trees, subtree overlap. To do this, you simply need to think about how you would 'print' or 'represent' the men in my anaolgy.
My implementation, its limitations and its potential
Firstly the only reason my code implementation takes in more parameters than should be needed (currentNode to be printed and node level) is because I can't easily move a line up in console when printing, so I have to map my lines first and print them in reverse. To do this I made a lineLevelMap that mapped each line of the tree to it's output (this might be useful for the future as a way to easily gather every line of the tree and also print it out at the same time).
//finds the height of the tree beforehand recursively, left to reader as exercise
int height = TreeHeight(root);
//the map that uses the height of the tree to detemrine how many entries it needs
//each entry maps a line number to the String of the actual line
HashMap<Integer,String> lineLevelMap = new HashMap<>();
//initialize lineLevelMap to have the proper number of lines for our tree
//printout by starting each line as the empty string
for (int i = 0; i < height + 1; i++) {
lineLevelMap.put(i,"");
}
If I could get ANSI escape codes working in the java console (windows ugh) I could simply print one line upwards and I would cut my parameter count by two because I wouldn't need to map lines or know the depth of the tree beforehand. Regardless here is my code that recurses in an in-order traversal of the tree:
public int InOrderPrint(CalcTreeNode currentNode, HashMap<Integer,String>
lineLevelMap, int level, int currentIndent){
//traverse left case
if(currentNode.getLeftChild() != null){
//go down one line
level--;
currentIndent =
InOrderPrint(currentNode.getLeftChild(),lineLevelMap,level,currentIndent);
//go up one line
level++;
}
//find the string length that already exists for this line
int previousIndent = lineLevelMap.get(level).length();
//create currentIndent - previousIndent spaces here
char[] indent = new char[currentIndent-previousIndent];
Arrays.fill(indent,' ');
//actually append the nodeData and the proper indent to add on to the line
//correctly
lineLevelMap.put(level,lineLevelMap.get(level).concat(new String(indent) +
currentNode.getData()));
//update the currentIndent for all lines
currentIndent += currentNode.getData().length();
//traverse right case
if (currentNode.getRightChild() != null){
//go down one line
level--;
currentIndent =
InOrderPrint(currentNode.getRightChild(),lineLevelMap,level,currentIndent);
//go up one line
level++;
}
return currentIndent;
}
To actually print this Tree to console in java, just use the LineMap that we generated. This way we can print the lines right side up
for (int i = height; i > -1; i--) {
System.out.println(lineLevelMap.get(i));
}
How it all really works
The InorderPrint sub function does all the 'work' and can recursively print out any Node and it's subtrees properly. Even better, it spaces them evenly and you can easily modify it to space out all nodes equally (just make the Nodedata equal or make the algorithim think it is). The reason it works so well is because it uses the Node's data length to determine where the next indent should be. This assures that the left subtree is always printed BEFORE the root and the right subtree, thus if you ensure this recursively, no left node is printed under it's root nor its roots root and so-on with the same thing true for any right node. Instead the root and all subroots are directly in the middle of their subtrees and no space is wasted.
An example output with an input of 3 + 2 looks like in console is:
And an example of 3 + 4 * 5 + 6 is:
And finally an example of ( 3 + 4 ) * ( 5 + 6 ) note the parenthesis is:
Ok but why Inorder?
The reason an Inorder traversal works so well is because it Always prints the leftmost stuff first, then the root, then the rightmost stuff. Exactly how we want our subtrees to be: everything to the left of the root is printed to the left of the root, everything to the right is printed to the right. Inorder traversal naturally allows for this relationship, and since we print lines and make indents based on nodeData, we don't need to worry about the length of our data. The node could be 20 characters long and it wouldn't affect the algorithm (although you might start to run out of actual screen space). The algorithm doesn't create any spacing between nodes but that can be easily implemented, the important thing is that they don't overlap.
Just to prove it for you (don't take my word for this stuff) here is an example with some quite long characters
As you can see, it simply adjusts based on the size of the data, No overlap! As long as your screen is big enough. If anyone ever figures out an easy way to print one line up in the java console (I'm all ears) This will become much much simpler, easy enough for almost anyone with basic knowledge of trees to understand and use, and the best part is there is no risk of bad overlapping errors.
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);
}
From your root, count the number of your left children. From the total number of left children, proceed with printing the root with the indention of the number of left children. Move to the next level of the tree with the decremented number of indention for the left child, followed by an initial two indentions for the right child. Decrement the indention of the left child based on its level and its parent with a double indention for its right sibling.
For an Array I find this much more concise. Merely pass in the array. Could be improved to handle very large numbers(long digit lengths). Copy and paste for c++ :)
#include <math.h>
using namespace std;
void printSpace(int count){
for (int x = 0; x<count; x++) {
cout<<"-";
}
}
void printHeap(int heap[], int size){
cout<<endl;
int height = ceil(log(size)+1); //+1 handle the last leaves
int width = pow(2, height)*height;
int index = 0;
for (int x = 0; x <= height; x++) { //for each level of the tree
for (int z = 0; z < pow(2, x); z++) { // for each node on that tree level
int digitWidth = 1;
if(heap[index] != 0) digitWidth = floor(log10(abs(heap[index]))) + 1;
printSpace(width/(pow(2,x))-digitWidth);
if(index<size)cout<<heap[index++];
else cout<<"-";
printSpace(width/(pow(2,x)));
}
cout<<endl;
}
}
Here is preorder routine that prints a general tree graph in a compact way:
void preOrder(Node* nd, bool newLine=false,int indent=0)
{
if(nd != NULL) {
if (newLine && indent) {
std::cout << "\n" << std::setw(indent) << ' '
} else if(newLine)
std::cout << "\n";
cout<< nd->_c;
vector<Node *> &edges=nd->getEdges();
int eSize=edges.size();
bool nwLine=false;
for(int i=0; i<eSize; i++) {
preOrder(edges[i],nwLine,indent+1);
nwLine=true;
}
}
}
int printGraph()
{
preOrder(root,true);
}
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);
Here is my code. It prints very well,maybe its not perfectly symmetrical.
little description:
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: https://i.stack.imgur.com/TtPXY.png
This code is written in C. It will basically print the tree "floor by floor".
Example of the output:
The function rb_tree_putchar_fd() can be replaced by a basic function that prints on screen, like std::cout << ... ;
SIZE_LEAF_DEBUG should be replaced by an int, and should be an even number. Use 6 for conveniance.
The function display() has one role: always print SIZE_LEAF_DEBUG characters on screen. I used '[' + 4 characters + ']' in my example. The four characters can be the string representation of an int for example.
//#include "rb_tree.h"
#define SIZE_LEAF_DEBUG 6
int rb_tree_depth(t_rb_node *root);
/*
** note: This debugging function will display the red/black tree in a tree
** fashion.
** RED nodes are displayed in red.
**
** note: The custom display func takes care of displaying the item of a node
** represented as a string of SIZE_LEAF_DEBUG characters maximum,
** padded with whitespaces if necessary. If item is null: the leaf is
** represented as "[null]"...
**
** note: the define SIZE_LEAF_DEBUG should be used by the display func.
** SIZE_LEAF_DEBUG should be an even number.
**
** note: Every node is represented by:
** - either whitespaces if NULL
** - or between squarred brackets a string representing the item.
*/
/*
** int max; //max depth of the rb_tree
** int current; //current depth while recursing
** int bottom; //current is trying to reach bottom while doing a bfs.
*/
typedef struct s_depth
{
int max;
int current;
int bottom;
} t_depth;
static void rb_tree_deb2(t_rb_node *node, t_depth depth, void (*display)())
{
int size_line;
int i;
i = 0;
size_line = (1 << (depth.max - ++depth.current)) * SIZE_LEAF_DEBUG;
if (!node)
{
while (i++ < size_line)
rb_tree_putchar_fd(' ', 1);
return ;
}
if (depth.current == depth.bottom)
{
while (i++ < (size_line - SIZE_LEAF_DEBUG) / 2)
rb_tree_putchar_fd(' ', 1);
if (node->color == RB_RED)
rb_tree_putstr_fd("\033[31m", 1);
display(node->item);
rb_tree_putstr_fd("\033[0m", 1);
while (i++ <= (size_line - SIZE_LEAF_DEBUG))
rb_tree_putchar_fd(' ', 1);
return ;
}
rb_tree_deb2(node->left, depth, display);
rb_tree_deb2(node->right, depth, display);
}
void rb_tree_debug(t_rb_node *root, void (*display)())
{
t_depth depths;
rb_tree_putstr_fd("\n===================================================="\
"===========================\n====================== BTREE DEBUG "\
"START ======================================\n", 1);
if (root && display)
{
depths.max = rb_tree_depth((t_rb_node*)root);
depths.current = 0;
depths.bottom = 0;
while (++depths.bottom <= depths.max)
{
rb_tree_deb2(root, depths, display);
rb_tree_putchar_fd('\n', 1);
}
}
else
rb_tree_putstr_fd("NULL ROOT, or NULL display func\n", 1);
rb_tree_putstr_fd("\n============================== DEBUG END ==========="\
"===========================\n==================================="\
"============================================\n\n\n", 1);
}