C++ Pointers, references and AVL Tree - c++

I am a college student and as my final task I have to create AVL Tree dictionary. I am trying to write it myself, I managed to write a lot of it already but I have one problem. When I am using all my getters and setters for random nodes or even vector of them, it works. But when I am trying to setRoot inside of Tree method, it fails. I mean, it works once but once I am trying to work with root calling it with avl.getRoot or as root in my implementation, it fails. My program is crashing. It's the hardest program I ever worked on. Could you solve my problem and give me some hints about important stuff ? Thank you in advance.
Main.cpp - Tests
Node n1("clown",1);
Node n2("cat",1);
Node n3("kid",1);
Node n4("wasp",1);
n1.setLSon(&n2);
std::cout<<"ENG: "<<n1.getLSon().getWord().getEng()<<std::endl;
n1.setRSon(&n3);
std::cout<<"ENG: "<<n1.getRSon().getWord().getEng()<<std::endl;
n1.setParent(&n4);
std::cout<<"ENG: "<<n1.getParent().getWord().getEng()<<std::endl;
if(n2.hasLSon)
n2.getLSon();
else
std::cout<<"n2 does not have a left son"<<std::endl;
AVL_Tree avl;
avl.addNode("cirrus",1);
avl.addNode("monkey",1);
std::cout<<"ENG: "<<avl.branches[0].getWord().getEng()<<std::endl;
std::cout<<"ENG: "<<avl.branches[1].getWord().getEng()<<std::endl;
avl.branches[0].setLSon(&avl.branches[1]);
std::cout<<"ENG: "<<avl.branches[0].getLSon().getWord().getEng()<<std::endl;
avl.branches[1].setParent(&avl.branches[0]);
std::cout<<"ENG: "<<avl.branches[1].getParent().getWord().getEng()<<std::endl;
/*Error is being called here*/
**std::cout<<"ROOT: "<<avl.getRoot().getWord().getEng()<<std::endl;**
}
Tree class : Problematic function
AVL_Tree::AVL_Tree()
{
root=NULL;
}
void AVL_Tree::sort()
{
}
Node AVL_Tree::getRoot()
{
return *root;
}
void AVL_Tree::addNode(std::string eng,int count)
{
int i=0;
branches.push_back(Node(eng,count));
for(i;i<branches.size();i++)
{
if(branches[i].getWord().getEng()==eng)
break;
}
if(branches.size()==1)
{
root=&(branches[i]);
std::cout<<"ROOT DODANY"<<endl;
std::cout<<root->getWord().getEng()<<std::endl;
}
else
std::cout<<"ROOTEM JEST: "<<root->getWord().getEng()<<std::endl;
if(!isBinary());
sort();
}
Tree Class
class AVL_Tree
{
public:
AVL_Tree();
void sort();
void addNode(std::string eng,int count);
void deleteNode(std::string eng);
Node findNode(std::string eng);
Node getRoot();
bool isBinary();
bool isNode(std::string eng);
std::vector<Node> branches;
private:
Node *root;
int leftFactor;
int rightFactor;
};
Node.cpp
Node::Node(std::string eng,int count):word(eng,count)
{
parent=NULL;
l_son=NULL;
r_son=NULL;
hasLSon=false;
hasRSon=false;
}
Node::~Node()
{
parent=NULL;
l_son=NULL;
r_son=NULL;
}
Word Node::getWord()
{
return word;
}
Node Node::getLSon()
{
return *l_son;
}
Node Node::getRSon()
{
return *r_son;
}
Node Node::getParent()
{
return *parent;
}
void Node::setLSon(Node *n)
{
l_son=n;
hasLSon=true;
}
void Node::setRSon(Node *n)
{
r_son=n;
hasRSon=true;
}
void Node::setParent(Node *n)
{
parent=n;
}
Node.h
class Node
{
public:
Node(std::string eng,int count);
~Node();
Word getWord();
Node getLSon();
Node getRSon();
Node getParent();
void setLSon(Node *node);
void setRSon(Node *node);
void setParent(Node *node);
bool hasLSon;
bool hasRSon;
private:
Node *parent;
Node *l_son;
Node *r_son;
Word word;
};

In your addNode you assign a pointer to an element of branches to root. A later call to addNode will add a new branch, reallocate the memory for the vector, and invalidate the root pointer. This results in the later crash when you try to use this invalid pointer.
You also have a semicolon after an if statement at the end of addNode that I don't think you want to be there. Compile with all the warnings turned on to be notified about things like this.

Related

Binary Tree with class in c++

I'm trying to write class for binary tree in c++ but I think in inserting function I have some problem it doesnt work correctly I'm begginer in c++ and I can't find the problem.
I should write this code without using "struct" it should Compeletly write with classes
I'm so sorry beacuse my code doesn't have any comment
and also sorry for bad English
Thank you very much
#include<iostream>
using namespace std;
///////////////////////////////////////////////////////////////////////////
class Tree
{
public:
Tree* left;
Tree* right;
string info;
Tree()
{
this->left=NULL;
this->right=NULL;
this->info="";
}
Tree(string info)
{
this->left=NULL;
this->right=NULL;
this->info=info;
}
Tree(string info,Tree* left,Tree* right)
{
this->left=left;
this->right=right;
this->info=info;
}
};
/////////////////////////////////////////////////////////////////////
class LinkedList
{
public:
Tree* root;
LinkedList()
{
root=NULL;
}
void mainInsert(Tree* newroot , string info)
{
if(newroot==NULL)
{
Tree* newNode = new Tree(info);
newroot=newNode;
return;
}
if(info.compare(newroot->info)==-1)
{
mainInsert(newroot->left,info);
}
else
{
mainInsert(newroot->right,info);
}
}
void mainPrintTree(Tree* newroot)
{
if(newroot==NULL)
{
return;
}
cout<<newroot->info<<endl;
mainPrintTree(newroot->left);
mainPrintTree(newroot->right);
}
void insert(string info)
{
mainInsert(this->root , info);
}
void printTree()
{
mainPrintTree(this->root);
}
};
///////////////////////////////////////////////////////////////////////////
int main()
{
LinkedList myTree;
myTree.insert("2");
myTree.insert("1");
myTree.insert("3");
myTree.insert("7");
myTree.insert("0");
myTree.printTree();
return 0;
}
Here is a (the?) culprit:
void mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
newroot = newNode; // Oops, only changing a local pointer here!
return;
}
...
It is a common error of beginners: you passed a pointer to a function, change that pointer and wonder why the original pointer is still unchanged... The reason is that apart from being able to change its pointee value, a pointer is a mere variable. So the function has its local copy of the pointer, and changing it has no effect in the caller. Here a simple way is probably to return the new root:
Tree* mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
return newNode;
}
// remember to return newroot in other branches...
Just use that in insert:
void insert(string info)
{
this->root = mainInsert(this->root , info);
}
But there are tons of possible improvements here, like separating the public interface from the private implementation, so I would advise you to post your code on Code Review as soon as is will work without errors...
Your mainInsert is wrong: after mainInsert(newroot->left,info);, newroot->left is not modified because that argument is passed by value (BTW read this SO article article, it's about C, not C++ but the concept is the same).
The simplest here is just to pass the node by reference, which makes your code even simpler:
void mainInsert(Tree* &subTree, string info)
{
if (subTree == NULL)
{
subTree = new Tree(info);
return;
}
if (info.compare(subTree->info) == -1)
{
mainInsert(subTree->left, info);
}
else
{
mainInsert(subTree->right, info);
}
}
I renamed the newroot parameter into subTree, because there is actually only one root per tree and every node of the tree is actually a also tree.
BTW: your question about writing this code without using struct is pointless, you don't use struct at all in your code.
Hint: try to write an iterative version of mainInsert. It's pretty simple and straightforward as the problem is not inherently recursive.

How to fix it in BST insertion and let the insertion function work

The code showed in Visual StudioThe InsertBSTNode function is wrong. But I don't know how to fix it. The requirement is that do not change the type of the function.
TreeNode
class TreeNode{
public:
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int x): data(x), left(NULL), right(NULL){}
};
InsertBSTNode
void InsertBSTNode(TreeNode* &root, int val){
// Input your code here.
if (root==NULL){
root->data=val;
root->left=root->right=NULL;}
else if(val<root->data)
root->left=InsertBSTNode(root->left,val);//error
else if(val>root->data)
root->right=InsertBSTNode(root->right,val);//error
return root;//error
};
So this is the code I think you are trying to write
void InsertBSTNode(TreeNode* &root, int val) {
if (root == NULL) {
root = new TreeNode;
root->data=val;
root->left=root->right=NULL;
}
else if (val<root->data)
InsertBSTNode(root->left,val);
else
InsertBSTNode(root->right,val);
}
I've fixed the invalid use of return values, and I've fixed the NULL pointer error by allocating a node at the place where you do the insert.
This is the solution for the question. Thanks for #john helping!
void InsertBSTNode(TreeNode* &root, int val){
if (root==NULL){
root = new TreeNode(val);
root->data=val;
root->left=root->right=NULL;}
else if(val<root->data)
InsertBSTNode(root->left,val);
else if(val>root->data)
InsertBSTNode(root->right,val);
};

How to pass the value from superclass to subclass in c++

I have made a superclass named "tree". I have constructed the tree in this class. Now, I want to pass the root of the constructed tree to another class which is a subclass of tree. But when I try to pass it, the subclass calls the supercalss constructor and sets it to NULL;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
This is the definition of my tree class. It just creates a tree with one node having value 5. Now I want to pass the new root created to a subclass of tree.
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
I create an object for tree first and then do createtree. Now, when I create an object for treeiterator, it's member p gets sets to NULL since supercalss constructor is also called. How can I just access the tree created in the superclass in subclass?
Full code:
#include <bits/stdc++.h>
using namespace std;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
void treeiterator::push(struct node *t)
{
while(t) {
s.push(t);
t = t->left;
}
}
bool treeiterator::hasnext()
{
return s.empty()?1:0;
}
int treeiterator::next()
{
struct node *t = s.top();
int val = t->val;
s.pop();
if(t->right) {
push(t->right);
}
return val;
}
int main()
{
tree t;
t.createtree();
t.preorder();
treeiterator it;
while(it.hasnext()) {
cout<<it.next()<<' ';
}
}
Because of inheritance every treeiterator is also a tree. This means
treeiterator treeIt;
treeIt.createtree();
will do what OP wants. There is no need to make a separate tree and moving the root around.
However this is a bit odd in the world of C++ because OP is under-using the constructor. For example, node could be:
struct node
{
node *left;
node *right;
int val;
node(int inval):
val(inval),
left(nullptr),
right(nullptr)
// the above is a Member Initializer List. It makes sure all of your
// members are initialized before the body of the constructor runs.
{
}
};
That bit after the : in the constructor is the Member Initializer List.
Now when you allocate a node it's initialized and ready to be linked. For tree
class tree
{
public:
struct node *root; // almost certainly should not be public.
// also should be a std::unique_ptr<node>
tree(int inval)
{
root = new node(5); // note new in place of malloc. new allocates
// storage and calls constructors. malloc should
// only be used in C++ in rare edge-cases.
}
/* obsolete
void createtree()
{
root = create(5);
}
*/
...
};
tree is assigned a root on allocation. treeiterator is a wee bit trickier because it must call tree's constructor to set up root.
class treeiterator:public tree
{
struct node *p; // Don't see the point off this
stack<struct node *> s; // or this, but that's another question
public:
treeiterator(int inval):
tree(inval) // call's tree's constructor
{
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
Allocating a treeiterator now guarantees that it is all ready to go with no further work.
treeiterator treeIt(5); // all done.
All of the above is covered within the first few chapters of any good C++ programming text. I recommend getting one and reading it, because right now it looks like you are trying to write bad C.
Off topic 1:
You are going to quickly find that this code is in violation of the Rule Of Three. What is The Rule of Three? If you don't know, read the link. It will save you much time and hair-pulling
Off Topic 2:
#include <bits/stdc++.h>
using namespace std;
Is a ticking time bomb. The first line includes the entire standard library, but only in GCC. Your code is now doing far, far more work than it need to to compile, is no longer standard C++, and is not portable to other compilers and may well break with the next revision of GCC. Don't use anything in bits. It internal compiler-specific stuff with no guarantees what-so-ever.
More here: Why should I not #include <bits/stdc++.h>?
The second line takes everything in the std namespace and places it in the global namespace. This leads to fun games like is reverse or std::reverse being called? Often this leads to insane and arcane compiler messages because the poor compiler is confused as hell, but sometimes it's not confused and picks the best choice among the many and silently breaks something else. Great fun debugging.
More here: Why is "using namespace std" considered bad practice?
Together you have the entire standard library pulled into your file AND stripped of it's proper namespace. This results in a vast minefield of potential hidden pain that is not worth any perceived time savings. One of the resulting bugs could cost more clean up than years of typing a few extra lines per file and characters.
No one want to clean up code with this stupid a mistake, so doing this in a professional setting can be costly.
First, you should not have root has public. This is a gross OO error. If you want it to be available to subclasses you should make it protected.

First time using classes in C++, what's going on?

I am trying to implement a custom tree structure, but I am getting a weird output.
enum letter{B,A,T,G,C,N};
struct Node {
int ltr;
Node* ptr;
};
class GTree
{
public:
GTree(int);
void insert(int);
private:
Node* root;
void insert(int l,Node* leaf);
};
GTree::GTree(int l)
{
root->ltr=l;
}
void GTree::insert(int l, Node *leaf)
{
cout<<leaf->ltr;
}
void GTree::insert(int l)
{
if(root==NULL)
{
insert(l, root);
}
else
{
root= new Node;
insert(l,root);
}
}
int main()
{
GTree tree=GTree(T);
tree.insert(T);
}
The output comes out as -2062064467 even though I was expecting 2. Whats going on here? I was looking at a simple BTree implementation, but intending to repurpose it for my desired data structure.
You didn't create a Node object when you first created the GTree object.
GTree::GTree(int l)
{
root->ltr=l;
}
should be
GTree::GTree(int l)
{
root = new Node();
root->ltr=l;
}
Also, make sure you have a destuctor to clean up the resources.
Something else I feel I should point out is that GTree::insert(int l, Node *leaf) perhaps doesn't do what you expect it to do.
cout<<leaf->ltr;
The code above only outputs the integer value in the node but not actually assigning it.
But perhaps you haven't completed that part yet. :-)
You hadn't initialized root, so root->ltr=l; produces undefined behavior. Add root = new Node(); first.
I ran your code and got the output 0 on Ubuntu 12.04 with gcc 4.6.3.

Custom Queue Class C++

So I'm trying to create a Singly-linked-list Queue. I'm trying to write a function to add elements, and everything adds fine, but the problem is that its FILO instead of FIFO. I'm not sure how to handle my front and rear pointers.
#include <iostream>
#include <string>
using namespace std;
class Queue{
public:
Queue();
//~Queue();
void add(const string & item);
//string remove();
// unsigned items() const;
void show() const;
private:
struct Node{
string data;
Node *next;
};
Node *rear;
Node *front;
unsigned elements;
};
Queue::Queue():elements(0),rear(NULL),front(NULL){}
//Queue::~Queue(){
//}
void Queue::add(const string & item){
Node *t=new Node;
t->data=item;
t->next=rear;
if(front==NULL)
front=t;
rear=t;
elements++;
}
void Queue::show() const{
Node *p=rear;
for(; p->next!=rear; p=p->next){
cout<<" "<<p->data;
}
cout<<"\n";
}
int main(){
Queue obj;
obj.add("I");
obj.add("Am");
obj.add("Super");
obj.add("Cool");
obj.show();
}
currently it is neither FIFO nor FILO bu JINO (just in, never out).
what you do is to insert on the rear end. and your show does iterate from rear to front, because thats the only linked direction.
for an effective FIFO you would need a remove from the front end of your queue. you will notice, that you can find the front element, but you have no easy way to find the second element that is needed to set the front pointer. this is the drawback of your single linked design, you have to iterate from the rear to the front to find the element pointing to front.
with a single linked list you can do a FILO (actually more likely named LIFO or stack)
for a FIFO a double linked list would be the better design.
if you want to stick to a single linked list you could do some recursion. you eliminate the front pointer cause it is useless.
void Queue::show_one(Node *p) const{
if (p->next!=rear) { // i kept the test for p->next!=rear
// either fix add or test for p->next!=NULL
show_one(p->next);
}
cout<<" "<<p->data;
}
void Queue::show() const{
show_one(rear);
cout<<"\n";
}
likewise you could write a remove()
to achieve, FILO(like STACK?),
When push(add), append your new element at the end( you will deal with rear pointer)
When pop, get rid of the element that rear pointer points to.
In you code, your rear pointer points to one element after end, which is null. So push takes O(n), and also pop cost O(n). Its not efficient. So considering double linked list may be better choice for easy implementation.
I figured out how to reverse the entire thing so it works properly now. Is it efficient? It took 1.06ms to run main.
#include <iostream>
#include <string>
using namespace std;
bool die(const string &msg);
class Queue{
public:
Queue();
~Queue();
void add(const string & item);
string remove();
unsigned items() const;
void show() const;
private:
struct Node{
string data;
Node *next;
};
Node *rear;
Node *front;
unsigned elements;
};
Queue::Queue():elements(0),rear(NULL),front(NULL){}
Queue::~Queue(){
unsigned el=items();
for(unsigned i=0; i<el; i++)
remove();
}
unsigned Queue::items()const{
return elements;
}
string Queue::remove(){
if(front==NULL) die("underflow");
Node *t=front;
string data=t->data;
front=t->next;
delete t;
elements--;
return data;
}
void Queue::add(const string &item){
Node *t=new Node;
t->data=item;
t->next=NULL;
if(front==NULL)
front=t;
else{
Node *t2=rear;
t2->next=t;
}
rear=t;
elements++;
}
void Queue::show() const{
Node *t=front;
for(unsigned i=0; i<items(); i++, t=t->next)
cout<<t->data<<'\n';
}
bool die(const string &msg){
cout<<"Error: "<<msg;
exit(EXIT_FAILURE);
}
int main(){
Queue obj;
obj.show();
obj.add("poo");
obj.add("cra");
obj.add("bil");
obj.add("shi");
obj.show();
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
}