Hi everyone this is my first time in Stackoverflow. I have a question regarding counting the occurrence of words in text file using C++. This is my code so far. I have to create an array struct of index of the word and the counter of each word then store all of them in an AVL tree. After opening the file and read a word, I look for it in the avl tree or trie. If it is there, use the node's index to increment the word's Cnt. If it is not there, add it to the word array and put its position in the next struct and put the structs position in the avl tree. Also I set the struct Cnt to 1. The problem I am having now is it seems like my program doesn't process the counting properly therefore it only prints out 0. Please give me recommendation on how I can fix the bug. Please find my code below:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <stdio.h>
#include <string>
#include <cctype>
#include <stdlib.h>
#include <stdbool.h>
using namespace std;
struct Node* insert(struct Node* node, int key) ;
void preOrder(struct Node *root) ;
void removePunct(char str[]);
int compareWord(char word1[], char word2[] );
struct Stats {
int wordPos, wordCnt;
};
Stats record[50000];
int indexRec = 0;
char word[50000*10] ;
int indexWord = 0;
int main() {
ifstream fin;
string fname;
char line[200], wordArray[500000];
cout << "Enter the text file name:" << endl;
cin >> fname;
fin.open(fname.c_str());
if (!fin) {
cerr << "Unable to open file" << endl;
exit(1);
}
struct Node *root = NULL;
while (!fin.eof() && fin >> line) { //use getline
for(int n=0,m=0; m!=strlen(line); m+=n) {
sscanf(&line[m],"%s%n",word,&n);
removePunct(word);
//strcpy(&wordArray[indexWord],word);
int flag = compareWord(wordArray, word);
if(flag==-1) {
strcpy(&wordArray[indexWord],word);
record[indexRec].wordPos = indexWord;
record[indexRec].wordCnt = 1;
root = insert(root, record[indexRec].wordPos);
indexWord+=strlen(word)+1;
// indexes of the word array
indexRec++;
cout << wordArray[indexWord] << " ";
} else
record[flag].wordCnt++;
cout << record[indexRec].wordCnt;
cout << endl;
}
/*for(int x = 0; x <= i; x++)
{
cout << record[x].wordPos << record[x].wordCnt << endl;
}*/
}
fin.close();
return 0;
}
void removePunct(char str[]) {
char *p;
int bad = 0;
int cur = 0;
while (str[cur] != '\0') {
if (bad < cur && !ispunct(str[cur]) && !isspace(str[cur])) {
str[bad] = str[cur];
}
if (ispunct(str[cur]) || isspace(str[cur])) {
cur++;
} else {
cur++;
bad++;
}
}
str[bad] = '\0';
for (p= str; *p!= '\0'; ++p) {
*p= tolower(*p);
}
return;
}
int compareWord(char word1[], char word2[] ) {
int x = strcmp(word1, word2);
if (x == 0 ) return x++;
if (x != 0) return -1;
}
struct Node {
int key;
struct Node *left;
struct Node *right;
int height;
};
// A utility function to get maximum of two integers
int max(int a, int b);
// A utility function to get height of the tree
int height(struct Node *N) {
if (N == NULL)
return 0;
return N->height;
}
// A utility function to get maximum of two integers
int max(int a, int b) {
return (a > b)? a : b;
}
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct Node* newNode(int key) {
struct Node* node = (struct Node*)
malloc(sizeof(struct Node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct Node *rightRotate(struct Node *y) {
struct Node *x = y->left;
struct Node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct Node *leftRotate(struct Node *x) {
struct Node *y = x->right;
struct Node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(struct Node *N) {
if (N == NULL)
return 0;
return height(N->left) - height(N->right);
}
// Recursive function to insert key in subtree rooted
// with node and returns new root of subtree.
struct Node* insert(struct Node* node, int key) {
/* 1. Perform the normal BST insertion */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key);
else if (key > node->key)
node->right = insert(node->right, key);
else // Equal keys are not allowed in BST
return node;
/* 2. Update height of this ancestor node */
node->height = 1 + max(height(node->left),
height(node->right));
/* 3. Get the balance factor of this ancestor
node to check whether this node became
unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then
// there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->key)
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node->right->key)
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node->left->key) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->key) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
void preOrder(struct Node *root) {
if(root != NULL) {
printf("%d ", root->key);
preOrder(root->left);
preOrder(root->right);
}
}
One problem (I cannot see if this is the only problem) is that you have code like this, deleting all the intermediate lines:
record[indexRec].wordCnt = 1;
if find word fails
indexRec++;
cout << record[indexRec].wordCnt;
So when you have a new word (if I understand the code correctly!) you are printing out the next record. One fix would be:
if (flag==-1)
cout << record[indexRec-1].wordCnt;
else
cout << record[indexRec].wordCnt;
There's a lot of other issues, like compareWord() is very wrong, you should decide if you really want to use C++ or just C with std::cout, the file reading code is odd, you're including both C and C++ versions of standard headers, etc, but these are issues for another question!
i have been trying to solve this problem by using binary trees, because i am starting to learn about them.
Please tell me if this problem can be solved by using binary trees or not, and if yes, what's wrong with my code for it that i've written so far(its in c++)?
it gives wrong answer...
The Problem:
Vasya has found a strange device. On the front panel of a device there are: a red button, a blue button and a display showing some positive integer. After clicking the red button, device multiplies the displayed number by two. After clicking the blue button, device subtracts one from the number on the display. If at some point the number stops being positive, the device breaks down. The display can show arbitrarily large numbers. Initially, the display shows number n.
Bob wants to get number m on the display. What minimum number of clicks he has to make in order to achieve this result?
Input
The first and the only line of the input contains two distinct integers n and m (1 ≤ n, m ≤ 104), separated by a space .
Output
Print a single number — the minimum number of times one needs to push the button required to get the number m out of number n.
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
struct Node{
int val;
Node* Left;
Node* Right;
};
Node* GetNode(int val){
Node* newnode = new Node();
newnode->val = val;
newnode->Left = NULL;
newnode->Right = NULL;
return newnode;
}
int BFS(Node* root, int m){
int ctr = 0;
queue<Node*> qu;
qu.push(root);
while(!qu.empty()){
Node* tmp = qu.front();
qu.pop();
if(tmp->val == m) return ctr;
ctr++;
if(tmp->Left != NULL) qu.push(tmp->Left);
if(tmp->Right != NULL) qu.push(tmp->Right);
}
}
int main(void){
int n, m;
scanf("%d%d", &n, &m);
Node* root = GetNode(n);
Node* tmp;
queue<Node*> qu;
qu.push(root);
while(!qu.empty()){
tmp = qu.front();
qu.pop();
if(tmp->val == m) break;
tmp->Left = GetNode(2 * tmp->val);
qu.push(tmp->Left);
if(tmp->val-1 >= 0){
tmp->Right = GetNode(tmp->val - 1);
qu.push(tmp->Right);
}
}
printf("%d\n", BFS(root, m));
}
The while loop in your main() is an infinite loop. There are no conditions that will terminate that loop. Your program keeps allocating memory for the queue, until it runs out of space.
Your continue should be a break. Still, this while() loop is very inefficient, due to the exponentially-growing queue that it generates.
You need to store the level of the node (root level: 0) because this will give you the steps you need to get m.
struct Node{
int val;
Node* Left;
Node* Right;
int lev;
};
Then, getNode will have one more parameter(level):
Node* GetNode(int val,int l){
Node* newnode = new Node();
newnode->val = val;
newnode->lev = l;
newnode->Left = NULL;
newnode->Right = NULL;
return newnode;
}
The root of the tree starts with level 0:
Node* root = GetNode(n,0);
And when you want to get a new node the level will be the level of the parent +1:
node->Left = GetNode(value,(node->lev)+1);
Your break is not in the most efficient place, you should stop your loop when you add a new node (with value tmp->val*2 or tmp->val-1) and any of these are m (and dont forget to update tmp, you will use it to print the answer).
Another important thing to make your algorithm efficient is to know when does your node should be add in the tree. One of them is "if them is if tmp->val-1 is less or equal 0 (number must always be positive). Also, if the node is higher than m, then it shouldn't increase, so tmp->left is going to be created only if tmp->val < m.
Finally, if you reach a number that is already in your tree, then you should add that node (this validation is done with !nit.count(x) that means "if I dont have any x in my map").
//this if comes inmediatly after reading n and m
if (n==m){
cout<<0<<endl;
return 0;
}
while(!qu.empty()){
tmp = qu.front();
qu.pop();
if (!nit.count(2 * tmp->val) && (tmp->val<m)){
tmp->Left = GetNode(2 * tmp->val,tmp->lev+1);
//cout<<2 * tmp->val<<endl;
if ((2 * tmp->val)==m){
tmp=tmp->Left; break;
}
nit[2 * tmp->val]++;
qu.push(tmp->Left);
}
if(!nit.count(tmp->val-1) && (tmp->val-1 > 0)){
tmp->Right = GetNode(tmp->val - 1,tmp->lev+1);
//cout<<tmp->val-1<<endl;
if ((tmp->val-1)==m){
tmp=tmp->Right; break;
}
nit[tmp->val-1]++;
qu.push(tmp->Right);
}
}
Now you have the answer:
printf("%d\n",tmp->lev);
This is the entire code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
using namespace std;
struct Node{
int val;
Node* Left;
Node* Right;
int lev;
};
Node* GetNode(int val,int l){
Node* newnode = new Node();
newnode->val = val;
newnode->lev = l;
newnode->Left = NULL;
newnode->Right = NULL;
return newnode;
}
int main(void){
int n, m;
map<int,int>nit;
scanf("%d%d", &n, &m);
if (n==m){
cout<<0<<endl;
return 0;
}
Node* root = GetNode(n,0);
nit[n++];
Node* tmp;
queue<Node*> qu;
qu.push(root);
while(!qu.empty()){
tmp = qu.front();
qu.pop();
if (!nit.count(2 * tmp->val) && (tmp->val<m)){
tmp->Left = GetNode(2 * tmp->val,tmp->lev+1);
//cout<<2 * tmp->val<<endl;
if ((2 * tmp->val)==m){
tmp=tmp->Left; break;
}
nit[2 * tmp->val]++;
qu.push(tmp->Left);
}
if(!nit.count(tmp->val-1) && (tmp->val-1 > 0)){
tmp->Right = GetNode(tmp->val - 1,tmp->lev+1);
//cout<<tmp->val-1<<endl;
if ((tmp->val-1)==m){
tmp=tmp->Right; break;
}
nit[tmp->val-1]++;
qu.push(tmp->Right);
}
}
printf("%d\n",tmp->lev);
}
Sorry for my English 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);
}
Below is a program which first build Binary tree from inorder and preorder and then find the node which contain largest balanced tree.
My both function for Buildtree and IsBalanced is right.
I am reading inorder and preorder from input.txt file; so in first iteration my program is showing correct output, but in the second iteration, it is not working.
I think that there is problem in deleting root.
After running above program you will get which problem I am talking about :
/* Tree - Program to find largest Balanced tree in given tree
#Date : 15 July 2012
This program works only for one input sample
*/
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
struct node
{
char data;
struct node* left;
struct node* right;
};
/* Prototypes for utility functions */
int search(string arr, int strt, int end, char value);
struct node* newNode(char data);
int isBalanced(struct node *root, int* height,int *max_size_ref, bool *is_bal_ref,char *val)
{
/* lh = Height of left subtree ,rh = Height of right subtree */
int lh = 0, rh = 0;
int left_flag=0;
int right_flag=0;
/* l will be true if left subtree is balanced
and r will be true if right subtree is balanced */
int l = 0, r = 0;
if(root == NULL)
{
*height = 0;
*is_bal_ref = 1;
return 0;
}
l = isBalanced(root->left, &lh, max_size_ref,is_bal_ref, val);
if (*is_bal_ref == 1)
left_flag=true;
r = isBalanced(root->right,&rh, max_size_ref,is_bal_ref, val);
if (*is_bal_ref == 1)
right_flag = true;
*height = (lh > rh? lh: rh) + 1;
if((lh - rh >= 2) || (rh - lh >= 2))
*is_bal_ref= 0;
/* If this node is balanced and left and right subtrees
are balanced then return true */
if(left_flag && right_flag && *is_bal_ref ){
*is_bal_ref= 1;
if (l + r + 1 > *max_size_ref)
{
*max_size_ref = l + r+ 1;
*val = root->data;}
return l + r + 1;
}
else
{
//Since this subtree is not Balanced, set is_bal flag for parent calls
*is_bal_ref = 0;
return 0;
}
}
struct node* buildTree(string in, string pre, int inStrt, int inEnd)
{
static int preIndex = 0;
if(inStrt > inEnd)
return NULL;
/* Pick current node from Preorder traversal using preIndex
and increment preIndex */
struct node *tNode = newNode(pre[preIndex++]);
/* If this node has no children then return */
if(inStrt == inEnd)
return tNode;
int inIndex = search(in, inStrt, inEnd, tNode->data);
/* Using index in Inorder traversal, construct left and
right subtress */
tNode->left = buildTree(in, pre, inStrt, inIndex-1);
tNode->right = buildTree(in, pre, inIndex+1, inEnd);
return tNode;
}
/* Function to find index of value in arr[start...end]
The function assumes that value is present in in[] */
int search(string arr, int strt, int end, char value)
{
int i;
for(i = strt; i <= end; i++)
{
if(arr[i] == value)
return i;
}
}
/* Helper function */
struct node* newNode(char data)
{
struct node* node = new (struct node);
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
/* This function is for inorder traversal */
void printInorder(struct node* node)
{
if (node == NULL)
return;
printInorder(node->left);
printf("%c ", node->data);
printInorder(node->right);
}
// function to free binary tree
void freeT(struct node* t ) //get root
{
if( t == NULL )
return;
if( t->left != NULL )
freeT( t->left );
if( t->right != NULL )
freeT( t->right);
delete(t); /* free(t) if c */
return;
}
/* Driver program to test above functions */
int main()
{
string line , inorder;
ifstream myfile ("input.txt");
ofstream myofile ("output.txt" );
if (myfile.is_open())
{
int len=0;
char data=NULL;
int height=0;
int max_size_ref=0;
bool is=false;
int size=0;
struct node *root = NULL;
while ( myfile.good() )
{
getline (myfile,line);
//cout << line << endl;
inorder=line;
getline (myfile,line);
//cout << line << endl;
len = line.size();
//cout<<"len="<<len;
root= buildTree(inorder, line, 0, len - 1);
data=NULL;
height=0;
max_size_ref=0;
is=false;
size=isBalanced(root, &height ,&max_size_ref, &is, &data);
if(data!=NULL)
{
myofile<<data;
myofile<<"\n";
//std::cout<<data;
}
else
{
myofile<<-1;
myofile<<"\n";
}
//printf("\n Inorder traversal of the constructed tree is \n");
//printInorder(root);
getchar();
//freeT(root);
//root=NULL;
}
myfile.close();
myofile.close();
}
//getchar();
return 0;
}
First run this program with input.txt containing below content and see output.txt
FDBGEHAC
ABDFEGHC
Then run above program with
FDBGEHAC
ABDFEGHC
FDCEBAJHGI
ABCDFEGHJI
Now see output.txt
You will get what I really want.
When using a tree or hierarchical structure ( collection ), you should keep the "root" variable, outside of the "while" loop, or other nodes.
This is a pseudocode, not intended to be full valid code, just an example:
int main()
{
...
struct node *root = NULL;
while ( myfile.good() )
{
// load tree, maybe change root
} // while
...
} // int main()
As you already check. "Root" is a pointer to an structure, and even that may change which node is root, you should have an external variable.
It seems you have a bug in buildTree that is triggered by the 2nd set of data. The bug causes infinite recursion, you get a "stackoverflow" :-) and your program crashes. You can confirm this by swapping lines 3 and 4 with lines 1 and 2 of the second input.txt sample data, your program will then die on the first iteration. You can run your program with gdb and will catch the stackoverflow. You can also put a print statement in buildTree and will see that it gets caught in infinite recursion.