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!
So my assignment requires us to use doubly linked lists to add or multiply numbers together and print them out. I was able to get it to work for whole numbers, but I can't figure out what to change to make it work for decimal numbers as well. Here's what I've got so far. I know it's not the most efficient or cleanest code, but I can try to clarify stuff if it doesn't make sense to you
For example this program will work fine if I do 50382+9281 or 482891*29734,but I need to get it to work for something like 4.9171+49.2917 or 423.135*59
EDIT: Pretend the int values are doubles. I changed it on my actual code, but the result when I do the math is still giving me a whole number so I need to figure out how to insert the decimal at the right place
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
using namespace std;
// A recursive program to add two linked lists
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
// A linked List Node
struct node
{
int data;
node* next;
node *prev;
};
typedef struct node node;
class LinkedList{
// public member
public:
// constructor
LinkedList(){
int length = 0;
head = NULL; // set head to NULL
node *n = new node;
n->data = -1;
n->prev = NULL;
head = n;
tail = n;
}
// This prepends a new value at the beginning of the list
void addValue(int val){
node *n = new node(); // create new Node
n->data = val; // set value
n->prev = tail; // make the node point to the next node.
// head->next = n;
// head = n;
// tail->next = n; // If the list is empty, this is NULL, so the end of the list --> OK
tail = n; // last but not least, make the head point at the new node.
}
void PrintForward(){
node* temp = head;
while(temp->next != NULL){
cout << temp->data;
temp = temp->next;
}
cout << '\n';
}
void PrintReverse(){
node* temp = tail;
while(temp->prev != NULL){
cout << temp->data;
temp = temp->prev;
}
cout << '\n';
}
void PrintReverse(node* in){
node* temp = in;
if(temp->prev== NULL){
if(temp->data == -1)
cout << temp->data << '\n';
}
else{
cout << temp->data << '\n';
temp = temp->prev;
PrintReverse(temp);
}
}
// returns the first element in the list and deletes the Node.
// caution, no error-checking here!
int popValue(){
node *n = head;
int ret = n->data;
head = head->next;
delete n;
return ret;
}
void swapN(node** a, node**b){
node*t = *a;
*a = *b;
*b = t;
}
node *head;
node *tail;
// Node *n;
};
/* A utility function to insert a node at the beginning of linked list */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node = (struct node*) malloc(sizeof(struct node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* A utility function to print linked list */
void printList(struct node *node)
{
while (node != NULL)
{
printf("%d", node->data);
node = node->next;
}
// printf("\n");
}
// A utility function to swap two pointers
void swapPointer( node** a, node** b )
{
node* t = *a;
*a = *b;
*b = t;
}
/* A utility function to get size of linked list */
int getSize(struct node *node)
{
int size = 0;
while (node != NULL)
{
node = node->next;
size++;
}
return size;
}
// Adds two linked lists of same size represented by head1 and head2 and returns
// head of the resultant linked list. Carry is propagated while returning from
// the recursion
node* addSameSize(node* head1, node* head2, int* carry)
{
// Since the function assumes linked lists are of same size,
// check any of the two head pointers
if (head1 == NULL)
return NULL;
int sum;
// Allocate memory for sum node of current two nodes
node* result = (node *)malloc(sizeof(node));
// Recursively add remaining nodes and get the carry
result->next = addSameSize(head1->next, head2->next, carry);
// add digits of current nodes and propagated carry
sum = head1->data + head2->data + *carry;
*carry = sum / 10;
sum = sum % 10;
// Assigne the sum to current node of resultant list
result->data = sum;
return result;
}
// This function is called after the smaller list is added to the bigger
// lists's sublist of same size. Once the right sublist is added, the carry
// must be added toe left side of larger list to get the final result.
void addCarryToRemaining(node* head1, node* cur, int* carry, node** result)
{
int sum;
// If diff. number of nodes are not traversed, add carry
if (head1 != cur)
{
addCarryToRemaining(head1->next, cur, carry, result);
sum = head1->data + *carry;
*carry = sum/10;
sum %= 10;
// add this node to the front of the result
push(result, sum);
}
}
// The main function that adds two linked lists represented by head1 and head2.
// The sum of two lists is stored in a list referred by result
void addList(node* head1, node* head2, node** result)
{
node *cur;
// first list is empty
if (head1 == NULL)
{
*result = head2;
return;
}
// second list is empty
else if (head2 == NULL)
{
*result = head1;
return;
}
int size1 = getSize(head1);
int size2 = getSize(head2) ;
int carry = 0;
// Add same size lists
if (size1 == size2)
*result = addSameSize(head1, head2, &carry);
else
{
int diff = abs(size1 - size2);
// First list should always be larger than second list.
// If not, swap pointers
if (size1 < size2)
swapPointer(&head1, &head2);
// move diff. number of nodes in first list
for (cur = head1; diff--; cur = cur->next);
// get addition of same size lists
*result = addSameSize(cur, head2, &carry);
// get addition of remaining first list and carry
addCarryToRemaining(head1, cur, &carry, result);
}
// if some carry is still there, add a new node to the fron of
// the result list. e.g. 999 and 87
if (carry)
push(result, carry);
}
node* reverse_list(node *m)
{
node *next = NULL;
node *p = m;
node *prev;
while (p != NULL) {
prev = p->prev;
p->prev = next;
next = p;
p = prev;
}
return prev;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Multiply2(node* n1, node* n2);
int digitsPerNode = 2;
node* result;
node* resultp = result;
node* resultp2 = result;
void Multiply(node* n1, node* n2)
{
if (n2->prev != NULL)
{
Multiply(n1, n2->prev);
}
Multiply2(n1, n2);
resultp2 = resultp = resultp->prev;
}
void Multiply2(node* n1, node* n2)
{
if (n1->prev != NULL)
{
Multiply2(n1->prev, n2);
}
if (resultp2 == NULL)
{
resultp2->data = 0;
result = resultp = resultp2;
}
int m = n1->data * n2->data + resultp2->data;
int carryon = (int)(m / pow(10, digitsPerNode));
resultp2->data = m % (int)pow(10, digitsPerNode);
if (carryon > 0)
{
if (resultp2->prev == NULL)
{
resultp2->prev->data = carryon;
}
else
{
resultp2->prev->data += carryon;
}
}
resultp2 = resultp2->prev;
}
/* int* buffer;
int lenBuffer = 0;
void multiplyHelper(int v, node* , int o);
void addToBuffer(int v, int i);
node* multiply(node* num1, node* num2)
{
if (num1 == NULL || num2 == NULL) return NULL;
int length1 = getSize(num1);
int length2 = getSize(num2);
if (length1 > length2) return multiply(num2, num1);
// initialize buffer
lenBuffer = length1 + length2;
buffer = new int[lenBuffer];
memset(buffer, 0, sizeof(int) * lenBuffer);
// multiply
int offset = 0;
node* anode = num1;
while (anode && anode->data!= -1)
{
multiplyHelper(anode->data, num2, offset);
anode = anode->prev;
offset++;
}
// transfer buffer to a linked list
node* h;
int pos = 0;
while (pos < lenBuffer && buffer[pos] == 0) pos++;
if (pos < lenBuffer)
{
node* temp;
temp->data = buffer[pos++];
h = temp;
anode = h;
while (pos < lenBuffer)
{
node* temp;
temp->data = buffer[pos++];
anode->prev = temp;
anode = anode->prev;
}
}
delete buffer;
lenBuffer = 0;
buffer = NULL;
cout << h->data << endl;
return h;
}
// multiply a single digit with a number
// called by multiply()
void multiplyHelper(int value, node* head, int offset)
{
// assert(value >= 0 && value <= 9 && head != NULL);
if (value == 0) return;
node* anode = head;
int pos = 0;
while (anode != NULL)
{
int temp = value * anode->data;
int ones = temp % 10;
if (ones != 0) addToBuffer(ones, offset + pos + 1);
int tens = temp / 10;
if (tens != 0) addToBuffer(tens, offset + pos);
anode = anode->prev;
cout << anode->data;
pos++;
}
}
// add a single digit to the buffer at place of index
// called by multiplyHelper()
void addToBuffer(int value, int index)
{
// assert(value >= 0 && value <= 9);
while (value > 0 && index >= 0)
{
int temp = buffer[index] + value;
buffer[index] = temp % 10;
value = temp / 10;
index--;
}
}*/
// Driver program to test above functions
int main(int argc, char *argv[])
{
char filename[50];
string name= argv[1];
string dig;
name.erase(0,9);//Parse input to only get input file.
ifstream file;
int digits;
for(int i = 0; i < name.length(); i++){
if(name.at(i) == ';'){
// dig = name.substr(0,name.length()-i);
name = name.substr(0,name.length()-i);
}
}
//cout << dig << endl;
//file.open("input.txt");
file.open(name.c_str());
digits = 2;
///////
///////////////////////////////////////////////////////////////////////
int words = 0;
int numbers = 0;
while(!file.eof()) //Goes through whole file until no more entries to input
{
string word;
getline(file,word); //Inputs next element as a string
// word << file;
//cout << word << '\n';
int x = 0;
node *head1 = NULL, *head2 = NULL, *result = NULL;
int counter = 0;
int t1index = 0; //keep tracks of nodes to multiply
int t2index = 0;
char operatorX;
LinkedList tempList1;
LinkedList tempList2;
while(x<word.length()) //Loops through each string input
{
//if(x<word.length()&&isalpha(word.at(x))) //Checks that x is in bounds and that char at position x is a letter
if(x<word.length()&&isdigit(word.at(x))) //Checks that x is in bounds and that char at position x is a number/digit
{
int start = x;
while(x<word.length()&&isdigit(word.at(x))) //Loops past the number portion
{
x++;
}
string temp = word.substr(start, x).c_str();
// cout << temp << '\n';
for(int i = 0; i < temp.length();i++){
tempList1.addValue(atoi(temp.substr(i, 1).c_str()));
// push(&head1, atoi(temp.substr(i, 1).c_str()));
counter++;
t1index++;
}
//search for the operator
while(x<word.length()){
if(x<word.length()&& (!isspace(word.at(x)) && !isdigit(word.at(x))))
{
while(x<word.length()&&(!isspace(word.at(x)) && !isdigit(word.at(x)))) //Loops past the letter portion
{
// cout << (word.at(x))<< '\n';
operatorX = word.at(x);
x++;
}
//search second value
while(x<word.length()){ //second value find
//start
if(x<word.length()&&isdigit(word.at(x))) //Checks that x is in bounds and that char at position x is a number/digit
{
int start = x;
while(x<word.length()&&isdigit(word.at(x))) //Loops past the number portion
{
x++;
}
string temp = word.substr(start, x).c_str();
for(int i = 0; i < temp.length();i++){
tempList2.addValue(atoi(temp.substr(i, 1).c_str()));
// push(&head2, atoi(temp.substr(i, 1).c_str()));
// cout << atoi(temp.substr(i, 1).c_str());
counter++;
}
//////START READING NUMBERS BACKWARDS
LinkedList finalList;
node* tempA = tempList1.tail;
node* tempB = tempList2.tail;
// multiply(tempA, tempB);
//ADDITION
while(tempA != NULL){
if(tempA->data != -1){
push(&head1,tempA->data);
// cout << tempA->data;
}
tempA = tempA->prev;
}
while(tempB != NULL){
if(tempB->data != -1){
push(&head2, tempB->data);
// cout << tempB->data;
}
tempB = tempB->prev;
}
// multiply(head1, head2);
// result = multiply(head1, head2);
// tempList1.PrintReverse();
addList(head1, head2, &result);
printList(head1);
cout << operatorX;
printList(head2);
cout << "=";
printList(result);
cout << endl;
}
else{
x++;
}
//end
}
}
else{
x++;
}
}
}
else //If char at position x is neither number or letter skip over it
{
x++;
}
}
}
}
Since you're working in C++, use a template/overloaded operators. Cast your ints to a floating point type as necessary. See e.g.:
C++ Template problem adding two data types
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);
}
Why the search and successor and predecessor returns -1?
// BST.cpp : main project file.
#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#define SIZE 10
using namespace std;
struct Node {
int value;
Node *left;
Node *right;
Node *parent;
};
struct BST {
Node *root;
};
void insert(int value, BST *tree) {
Node *x = tree->root;
Node *y = NULL;
Node *z = (Node *) malloc(sizeof(Node));
z->left = NULL;
z->right = NULL;
z->value = value;
// Add your code here
while (x!=NULL){
y=x;
if (z->value < x->value)
x= x->left;
else x = x->right;
}
z->parent=y;
if (y==NULL)
tree->root=z;
else if (z->value <y->value)
y->left =z;
else y->right =z;
}
Node *search(int key, Node *n) {
if (n== NULL || key == n->value)
return n;
if (key < n->value)
search(key, n->left);
else
search(key, n->right);
}
Node *min(Node *n) {
if (n == NULL || n->left == NULL)
return n;
else
return min(n->left);
}
Node *max(Node *n) {
if (n == NULL || n->right == NULL)
return n;
else
return max(n->right);
}
Node *successor(int value, Node *n) {
Node *y = NULL;
Node *x = search(value, n);
if (x == NULL)
return NULL;
if (x->right != NULL)
return min(x->right);
y = x->parent;
while (y != NULL && x == y->right) {
x = y;
y = y->parent;
}
return y;
}
Node *predecessor(int value, Node *n) {
Node *x = search(value, n);
Node *y = NULL;
if (x == NULL)
return NULL;
if (x->left != NULL)
return max(x->left);
y = x->parent;
while (y != NULL && x == y->left) {
x = y;
y = y->parent;
}
return y;
}
Node *remove(int value, BST *tree) {
Node *z = search(value, tree->root);
Node *y = NULL, *x = NULL;
if (z == NULL) return NULL;
if (z->left == NULL || z->right == NULL)
y = z;
else
y = successor(value, z);
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL)
x->parent = y->parent;
if (y->parent == NULL)
tree->root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
if (y != z) {
int tmp = z->value;
z->value = y->value;
y->value = tmp;
}
return y;
}
// ascending sort function
void sortAsc(Node *node) {
//Add your code here
//inorder
if (node->left!=NULL)
sortAsc(node->left);
cout<<node->value<<" ";
if (node->right!=NULL)
sortAsc(node->right);
}
// descending sort function
void sortDes(Node *node) {
// Add your code here
//inorder
if (node->right!=NULL)
sortDes(node->right);
cout<<node->value<<" ";
if (node->left!=NULL)
sortDes(node->left);
}
void clear(BST *tree) {
Node *n = NULL;
while (tree->root != NULL) {
n = remove(tree->root->value, tree);
free(n);
}
}
int main() {
int A[] = {3, 5, 10, 4, 8, 9, 1, 4, 7, 6};
Node *node = NULL;
BST *tree = (BST *) malloc(sizeof(BST));
tree->root = NULL;
// build BST tree
cout << "Input data:\n\t";
for (int i=0; i<SIZE; i++) {
cout << A[i] << " "; // by the way, print it to the console
insert(A[i], tree); // You need to complete TASK 1, so that it can work
}
// sort values in ascending order
cout << "\n\nAscending order:\n\t";
sortAsc(tree->root); // You need to complete TASK 2. Otherwise you see nothing in the console
// sort values in descending order
cout << "\n\nDescending order:\n\t";
sortDes(tree->root); // TASK 2 also!
// Find minimum value
if (tree->root != NULL)
cout << "\n\nMin: " << min(tree->root)->value;
// Find maximum value
if (tree->root != NULL)
cout << "\n\nMax: " << max(tree->root)->value;
// delete 4
cout << "\n\nDelete 4 and add 2";
//free(remove(4, tree)); // You need to complete TASK 3, so that remove(int, BST *) function works properly
// we also need to release the resource!!!
// insert 2
insert(2, tree); // It belongs to TASK 1 too.
cout << "\n\nAscending order:\n\t";
sortAsc(tree->root); // TASK 2!!
// Find the successor of 5, -1 means no successor
node = search(5, tree->root);
cout << "\n\nSearch of 5 is: " << (node != NULL?node->value:-1);
// Find the successor of 5, -1 means no successor
node = successor(5, tree->root);
cout << "\n\nSuccessor of 5 is: " << (node != NULL?node->value:-1);
// Find the predecessor of 5. -1 means no predecessor
node = predecessor(5, tree->root);
cout << "\n\nPredecessor of 5 is: " << (node != NULL?node->value:-1);
cout << "\n\n";
// clear all elements
clear(tree); // delete all nodes and release resource
free(tree); // delte the tree too
system("Pause");
}
Well there is a bug in your recursive search for starters you need to have all paths return values like this:
Node *search(int key, Node *n) {
if (n== NULL || key == n->value)
return n;
if (key < n->value)
return search(key, n->left);
else
return search(key, n->right);
}
Apart from that I'm inclined to say try debugging your own code first and giving more details about what you've found rather than just posting code and asking what's wrong with it. You're liable to get some real smart ass answers here otherwise ;)