The display for my binary tree in-order traversal is wrong. I cant figure out what I'm doing wrong. The output is showing up at 1-15 when the height is 4 (including level 0 as 1) instead of showing up as : 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15.
main:
#include <iostream>
#include "math.h"
#include "bintree.h"
using namespace std;
int main()
{
binary_tree bin;
int tmp, num, height;
cout << "Please enter a height that you wish to see: " ;
cin >> height;
cout << endl << endl;
bin.insert(num, height);
cout << "The In-Order Traversal is: " ;
bin.displayinorder();
cout << endl << endl;
system("Pause");
return 0;
}
void binary_tree::insert(int num, int height)
{
num = pow(2, height);
for(int i = 1; i < num; i++)
{
node* t = new node;
node* parent;
t-> data = i;
t-> left = NULL;
t-> right = NULL;
parent = NULL;
if(isEmpty()) root = t;
else
{
node* curr;
curr = root;
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 binary_tree::displayinorder()
{
inorder(root);
}
void binary_tree::inorder(node* p)
{
if(p)
{
inorder(p -> left);
cout<< " " << p->data <<" ";
inorder(p -> right);
}
}
void binary_tree::displaypreorder()
{
preorder(root);
}
void binary_tree::preorder(node* p)
{
if(p != NULL)
{
cout<<" "<< p -> data <<" ";
preorder(p -> left);
preorder(p -> right);
}
else return;
}
header:
#ifndef BINTREE_H
#define BINTREE_H
#include <cstdlib> // Provides NULL and size_t
class binary_tree
{
private:
struct node
{
node* left;
node* right;
int data;
};
node* root;
public:
binary_tree()
{
root = NULL;
}
bool isEmpty() const
{
return root==NULL;
}
void displayinorder();
void inorder(node*);
void displaypreorder();
void preorder(node*);
void insert(int, int);
};
#endif
I think you are unclear what in-order means. 1 .. 15 is the expected output for in-order traversal of a binary search tree containing the values 1 .. 15. The sequence you gave sounds like pre-order on a balanced binary search tree.
In other words, your traversal code is correct for in-order traversal.
That said, your tree generation code does not produce a balanced tree. An in-order traversal won't expose that, but a pre-order or post-order traversal will. Because you insert all of the values in increasing sequential order, you will get a tree made entirely of right children. Add some cout statements to your traversal to see what I mean.
Related
I am trying to create a binary tree using C++ classes and pointers. The tree is being initialized properly. However, when I add nodes to the tree, instead of adding them to the left or right sub-tree, the root node gets overwritten. I tried printing the inorder value to check if the nodes are added correctly or not, but that also prints nothing.
Here is the code for the same.
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include <cstdio>
using namespace std;
class Node{
private:
Node *left;
Node *right;
public:
int number;
Node(int number){
this->number = number;
this->left = NULL;
this->right = NULL;
}
void set_left_node(Node *node){
this->left = node;
}
void set_right_node(Node *node){
this->right = node;
}
Node* read_left_node(){
return this->left;
}
Node* read_right_node(){
return this->right;
}
};
class Binary_Tree{
public:
Node *root;
Binary_Tree(){
this->root = NULL;
}
Node* read_root(){
return this->root;
}
Node* insert_node(Node *root, Node node){
if(!root){
root = &node;
cout << "Inserted " << node.number << " " << root << endl;
return root;
}
else{
cout << "Root and node values " << root->number << " " << node.number << endl;
if(root->number < node.number){
root->set_right_node(insert_node(root->read_right_node(), node));
}
else{
root->set_left_node(insert_node(root->read_left_node(), node));
}
}
return root;
}
void inorder(Node *root){
if (root != NULL){
inorder(root->read_left_node());
cout<<root->number<<" ";
inorder(root->read_right_node());
}
}
};
int main(){
Binary_Tree bt = Binary_Tree();
bt.root = bt.insert_node(bt.root, Node(34));
bt.root = bt.insert_node(bt.root, Node(17));
bt.root = bt.insert_node(bt.root, Node(56));
cout << "Inorder" << endl;
bt.inorder(bt.root);
return 0;
}
Output:
I just wanted to implement a TreeNode class that works similar to that of a struct node for a tree implementation.
Everything is working fine except for the output that is including 0 at the beginning of the inOrder traversal. Can anyone please explain it to me why is that happening?
Input:
22,1,2,3,5,4,11,20,19,24,21
Output:
0 1 2 3 4 5 11 19 20 21 22 24
#include <bits/stdc++.h>
using namespace std;
class TreeNode{
public:
int data;
TreeNode* left;
TreeNode* right;
TreeNode(){
left = NULL;
right = NULL;
}
TreeNode(int val){
data = val;
left = NULL;
right = NULL;
}
};
void insertInorder(TreeNode* cur, int d){
if(d <= cur->data){
if(cur->left == NULL)
cur->left = new TreeNode(d);
else
insertInorder(cur->left,d);
}
else{
if(cur->right == NULL)
cur->right = new TreeNode(d);
else
insertInorder(cur->right,d);
}
}
TreeNode* makeTree(vector<int> v){
TreeNode* root = NULL;
for(int start = 0; start <= v.size(); start++){
if(start == 0){
root = new TreeNode();
root->data = v[0];
}
insertInorder(root,v[start]);
}
return root;
}
void printInorder(TreeNode* node)
{
if (node == NULL)
return;
/* first recur on left child */
printInorder(node->left);
/* then print the data of node */
cout << node->data << " ";
/* now recur on right child */
printInorder(node->right);
}
int main(){
vector<int> x = {22,1,2,3,5,4,11,20,19,24,21};
TreeNode* r = makeTree(x);
printInorder(r);
return 0;
}
Edit:
To the people visiting this questions at a future date. Better practices states that we shouldn't use
#include <bits/stdc++.h>
using namespace std;
Using namespace std can result into future namespace collisions in the code. For reference here.
I did the same mistake but I won't be doing this from now on.
Please refer to the link provided by #Jabberwocky here
To learn implementation of binary search tree,
I created a class bst and am facing problem in its add_node_private function.
bst.cpp -
#include <iostream>
#include <cstdlib>
using namespace std;
#include "bst.h"
// bst constructor
bst::bst() {
root = nullptr;
}
// methods of binary search tree
bst::node* bst::create_leaf(int a) { // creating a leaf with key
node* leaf = new node;
leaf->key = a;
leaf->left = nullptr;
leaf->right = nullptr;
return leaf;
}
// adding a leaf to the tree
void bst::add_leaf(int k) {
bst::add_leaf_private(k, root); // just calls the private function
// providing it with root
}
void bst::add_leaf_private(int k, node* ptr) {
if (ptr == nullptr) {
ptr = create_leaf(k);
cout << k << " added\n";
return;
}
if (k > ptr->key) {
cout << "went left of " << ptr->key << endl;
add_leaf_private(k, ptr->right);
}
if (k < ptr->key) {
cout << "went right of " << ptr->key << endl;
add_leaf_private(k, ptr->left);
}
if (k == ptr->key) {
cout << "key " << k << " already exists\n";
}
}
bst.h
#ifndef _BST_H
#define _BST_H
class bst
{
private:
struct node{
int key;
node* left;
node* right;
};
//private methods
void add_leaf_private(int k,node* ptr);
//void print_private(node* ptr);
public:
node* root=nullptr;
//bst constructor
bst();
//public methods
node* create_leaf(int k);
void add_leaf(int k);
//void print();
};
#endif // _BST_H
When I add leaves, I output shows that they were added (like this- 5 added)
main.cpp
#include <iostream>
#include <cstdlib>
#include "bst.h"
using namespace std;
int main(){
bst b1;
int tree_keys[]{50,70,21,4,32,64,15,51,14,100,83,2,3,70,87,90};
for(int x: tree_keys){
b1.add_leaf(x);
}
cout<<"root"<<b1.root<<endl;
return 0;
}
But I don't see any statement went left of ... or went right of ... which I was expecting. And later I checked and found out even after adding a bunch of nodes, I have my root==nullptr and I don't know where the nodes were being added then?
you are never updating root. Its always nullptr
you need
void bst::add_leaf_private(int k, node* ptr) {
if (ptr == nullptr) {
ptr = create_leaf(k);
root = ptr;
cout << k << " added\n";
return;
}
I made a stupid mistake of using ptr in the function add_leaf_private by value. I should have passed it by reference as I intend to change it in the function. Replacing ptr with &ptr solved the problem.
So I've posted about this recently, but I'm still at a loss for what is going wrong. Specifically, I can't seem to figure out what's causing my AVL Tree to take so long to sort. I read in a file of 500,000 random, unsorted numbers to sort by using a vector in a for loop to feed the tree the numbers one at a time. Now, I've also tested using a normal BST, as someone mentioned that having to create so many nodes one at a time might be why it's taking so long, but that completed in only 5 seconds, with only 12,164 nodes skipped due to being duplicates. My AVL Tree is taking upwards of 3 hours just to sort half the list, so something must be going wrong. Can anyone figure out what it is? As far as I know, the rebalancing and insertion logic is correct, because whenever I ran a bunch of test cases on it they all came out fine. I can't seem to track down where the problem is. Here's my full code for anyone that wants to check it out. Main is kind of a mess right now because of all the stuff I've included for testing purposes (like the tracking loop), but most of that will be gone in the final version.
EDIT:
This question has been answered.
#include <iostream>
#include<iomanip>
#include <time.h>
#include <vector>
#include <fstream>
using namespace std;
vector<int> numbers;
struct node
{
public:
int data, height;
node *leftChild, *rightChild;
};
node* root = NULL;
int findMin(node *p) // finds the smallest node in the tree
{
while (p->leftChild != NULL)
p = p->leftChild;
return p->data;
}
int findMax(node *p) // finds the largest node in the tree
{
while(p->rightChild != NULL)
p = p->rightChild;
return p->data;
}
int max(int a, int b) // gets the max of two integers
{
if(a > b)
return a;
else
return b;
}
int height(node *p) // gets the height of the tree
{
if(p == NULL)
return -1;
else
{
p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
}
return p->height;
}
node* newNode(int element) // helper function to return a new node with empty subtrees
{
node* newPtr = new node;
newPtr->data = element;
newPtr->leftChild = NULL;
newPtr->rightChild = NULL;
newPtr->height = 1;
return newPtr;
}
node* rightRotate(node* p) // function to right rotate a tree rooted at p
{
node* child = p->leftChild; // rotate the tree
p->leftChild = child->rightChild;
child->rightChild = p;
// update the height for the nodes
p->height = height(p);
child->height = height(child);
// return new root
return child;
}
node* leftRotate(node* p) // function to left rotate a tree rooted at p
{
node* child = p->rightChild; // perform the rotation
p->rightChild = child->leftChild;
child->leftChild = p;
// update the heights for the nodes
p->height = height(p);
child->height = height(child);
// return new root
return child;
}
int getBalance(node *p)
{
if(p == NULL)
return 0;
else
return height(p->leftChild) - height(p->rightChild);
}
// recursive version of BST insert to insert the element in a sub tree rooted with root
// which returns new root of subtree
node* insert(node*& p, int element)
{
// perform the normal BST insertion
if(p == NULL) // if the tree is empty
return(newNode(element));
if(element < p->data)
{
p->leftChild = insert(p->leftChild, element);
}
else
{
p->rightChild = insert(p->rightChild, element);
}
// update the height for this node
p->height = height(p);
// get the balance factor to see if the tree is unbalanced
int balance = getBalance(p);
// the tree is unbalanced, there are 4 different types of rotation to make
// Single Right Rotation (Left Left Case)
if(balance > 1 && element < p->leftChild->data)
{
return rightRotate(p);
}
// Single Left Rotation (Right Right Case)
if(balance < -1 && element > p->rightChild->data)
{
return leftRotate(p);
}
// Left Right Rotation (double left rotation)
if(balance > 1 && element > p->leftChild->data)
{
p->leftChild = leftRotate(p->leftChild);
return rightRotate(p);
}
// Right Left Rotation
if(balance < -1 && element < p->rightChild->data)
{
p->rightChild = rightRotate(p->rightChild);
return leftRotate(p);
}
// cout << "Height: " << n->height << endl;
// return the unmodified root pointer in the case that the tree does not become unbalanced
return p;
}
void inorder(node *p)
{
if(p != NULL)
{
inorder(p->leftChild);
cout << p->data << ", ";
inorder(p->rightChild);
}
}
void preorder(node *p)
{
if(p != NULL)
{
cout << p->data << ", ";
preorder(p->leftChild);
preorder(p->rightChild);
}
}
void print(node* root)
{
/*cout << "Min Value: " << findMin(root) << endl;
cout << "Max Value: " << findMax(root) << endl;
cout << "Pre Order: ";
preorder(root); */
cout << endl << "Inorder: ";
inorder(root);
cout << endl << endl << endl << endl;
}
void read()
{
int num;
ifstream file_save("data.txt");
if(file_save.is_open())
{
while(!file_save.eof())
{
file_save >> num;
numbers.push_back(num);
}
file_save.close();
}
else
{
cout << "Error in opening file!!" << endl;
}
}
int main()
{
double duration;
time_t begin = time(0);
read();
int x = 0;
int track = 0;
for (std::vector<int>::const_iterator i = numbers.begin(); i != numbers.begin() + 100000; ++i)
{
root = insert(root, numbers[x]);
x++;
track++;
if( (track % 10000) == 0)
{
cout << track << " iterations" << endl;
time_t now = time(0);
cout << now - begin << " seconds" << endl;
}
}
time_t end = time(0);
duration = end - begin;
// print(root);
cout << "The algorithm took " << duration << " seconds to complete." << endl;
return 0;
}
There are many problems with this code.
while(eof) is wrong.
The main loop expects exactly 100000 elements.
All key comparisons are exact (<, >). There are no rotations performed when a duplicate element is inserted. Thus a tree of identical elements will not be balanced at all.
The height of an empty tree is hardcoded to -1, but the height of a single-node three is initially set to 1, thus violating the invariant height(node) = 1+max(height(node->leftChild))+height(node->rightChild)).
height traverses the entire tree every time it is called, thus making insertion O(n).
So, it seems to me that the reason that it was taking so long was because of too many recursive calls all over the place. This modified code has less recursive calls and thus bogs down the CPU with less stacks to have to process. At least, that's what I'm getting out of this.
void newHeight(node* p)
{
double leftHeight = height(p->leftChild);
double rightHeight = height(p->rightChild);
if(leftHeight > rightHeight)
p->height = leftHeight;
else
p->height = rightHeight;
}
node* rotateright(node* p) // the right rotation round p
{
node* q = p->leftChild;
p->leftChild = q->rightChild;
q->rightChild = p;
newHeight(p);
newHeight(q);
return q;
}
node* rotateleft(node* q) // the left rotation round q
{
node* p = q->rightChild;
q->rightChild = p->leftChild;
p->leftChild = q;
newHeight(q);
newHeight(p);
return p;
}
node* rebalance(node* p) // p node balance
{
newHeight(p);
if( getBalance(p)==2 )
{
if( getBalance(p->rightChild) < 0 )
p->rightChild = rotateright(p->rightChild);
return rotateleft(p);
}
if (getBalance(p)==-2 )
{
if( getBalance(p->leftChild) > 0 )
p->leftChild = rotateleft(p->leftChild);
return rotateright(p);
}
return p; // no balance needed
}
node* insert(node* p, int element) // k key insertion in the tree with p root
{
if(!p) return newNode(element);
if(element < p->data)
p->leftChild = insert(p->leftChild, element);
else
p->rightChild = insert(p->rightChild, element);
return rebalance(p);
}
I am having difficulty printing out an Inorder binary tree. When I run my program and enter my input, it prints the Inorder after each character.
For example, if I enter ABCD, it will print:
Inorder: A
Inorder: AB
Inorder: ABC
Inorder: ABCD
However I only want to print out that last line.
This is the code that I have:
#include <iostream>
using namespace std;
template <class T>
class BinaryTree
{
private:
struct TreeNode
{
TreeNode *left;
TreeNode *right;
T data;
};
TreeNode *root;
public:
BinaryTree()
{
root = NULL;
}
void Inorder(TreeNode *n)
{
if(n != NULL)
{
Inorder(n -> left);
cout<< n -> data;
Inorder(n -> right);
}
}
void PrintInorder()
{
Inorder(root);
}
void InsertData(T data)
{
TreeNode *t = new TreeNode;
TreeNode *parent;
t -> data = data;
t -> left = NULL;
t -> right = NULL;
parent = NULL;
//is this a new tree?
if (isEmpty())
root = t;
else
{
TreeNode *curr;
curr = root;
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;
}
}
bool isEmpty()
{
return (root == NULL);
}
};
int main()
{
BinaryTree <char> BT;
char num;
while (cin >> num)
{
BT.InsertData(num);
cout << "Inorder: ";
BT.PrintInorder();
cout << endl;
}
return 0;
}
Don't print anything until you've read all the numbers.
while (cin >> num)
{
BT.InsertData(num);
}
cout << "Inorder: ";
BT.PrintInorder();
cout << endl;