my program crashes after running - c++

well this is my code and basically what i am trying to do is for my program to take words out of a text file that i prepared and to pass it to my program and count the amount of unique words, and to print out the unique word with the count on the side of it. i have cleared up all the errors i had but now i am stuck as it crashes every time i try to run it.
i would appreciate if someone could enlighten me on where i have done wrong on.
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
class BST
{
public:
BST ();
void insert (char*);
void printBST () const;
bool findNode (char*) const;
private:
struct Node;
typedef Node* NodePtr;
struct Node
{
char *word;
int count;
NodePtr left, right;
};
NodePtr root;
int compareVP (char*, char*) const;
void insert (NodePtr&, char*);
void inorderPrint (NodePtr) const;
bool findNode (NodePtr, char*) const;
};
int main ()
{
BST t;
char word[25];
ifstream readfile("infile.txt");
if(!readfile)
{
cout << "File could not be opened/found";
return 0;
}
while(readfile>> word)
{
t.insert(word);
}
if(readfile.eof())
t.printBST ();
}
BST::BST ()
{
root = NULL;
}
void BST::insert (char* word)
{
insert (root, word);
}
void BST::printBST () const
{
inorderPrint (root);
}
bool BST::findNode (char* word) const
{
return findNode (root, word);
}
int BST::compareVP (char* item1, char* item2) const
{
char* value1 = item1;
char* value2 = item2;
if (strcmp(value1,value2)==0)
return 0;
else if (strcmp(value1,value2)>0)
return 1;
else
return -1;
}
void BST::insert (NodePtr& root, char* word)
{
if (root == NULL)
{
NodePtr temp = new Node;
temp -> word = word;
temp -> left = NULL;
temp -> right = NULL;
root = temp;
}
else if (compareVP (root -> word, word) > 0)
insert (root -> left, word);
else if (compareVP (root -> word, word) < 0)
insert (root -> right, word);
else if (compareVP (root -> word, word) == 0)
root -> count++;
}
void BST::inorderPrint (NodePtr root) const
{
cout << "Word\tCount\n";
if (root != NULL)
{
inorderPrint (root -> left);
cout << root -> word << "\t";
cout << root -> count << "\n";
inorderPrint (root -> right);
}
else
cout << endl;
}
bool BST::findNode (NodePtr root, char* word) const
{
if (root == NULL)
return false;
else
{
int k = compareVP (root -> word, word);
if (k == 0)
return true;
else if (k > 0)
return findNode (root -> left, word);
else
return findNode (root -> right, word);
}
}

One problem here:
char* word; // Pointer contains reference to undef areal of memory
while(readfile >> word) // you trying save line to undef area - result is unpredictable
2nd problem:
In function insert() you just attach to node pointer, and reuse this pointer on levels upper.
Possible simple solution:
char word[1000];
while(readfile >> word)
{
t.insert(strdup(word));
}

Changed print method. and a line for the insertion.
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
class BST
{
public:
BST ();
void insert (char*);
void printBST () const;
bool findNode (char*) const;
private:
struct Node;
typedef Node* NodePtr;
struct Node
{
char *word;
int count;
NodePtr left, right;
};
NodePtr root;
int compareVP (char*, char*) const;
void insert (NodePtr&, char*);
void inorderPrint (NodePtr) const;
bool findNode (NodePtr, char*) const;
};
int main ()
{
BST t;
char word[25];
ifstream readfile("infile.txt");
if(!readfile)
{
cout << "File could not be opened/found";
return 0;
}
while(readfile>> word)
{
t.insert(strdup(word));
}
if(readfile.eof())
t.printBST ();
}
BST::BST ()
{
root = NULL;
}
void BST::insert (char* word)
{
insert (root, word);
}
void BST::printBST () const
{
cout << "Word\tCount\n";
inorderPrint (root);
}
bool BST::findNode (char* word) const
{
return findNode (root, word);
}
int BST::compareVP (char* item1, char* item2) const
{
char* value1 = item1;
char* value2 = item2;
if (strcmp(value1,value2)==0)
return 0;
else if (strcmp(value1,value2)>0)
return 1;
else
return -1;
}
void BST::insert (NodePtr& root, char* word)
{
if (root == NULL)
{
NodePtr temp = new Node;
temp -> word = word;
temp -> left = NULL;
temp -> right = NULL;
temp -> count = 1;
root = temp;
}
else if (compareVP (root -> word, word) > 0)
insert (root -> left, word);
else if (compareVP (root -> word, word) < 0)
insert (root -> right, word);
else if (compareVP (root -> word, word) == 0)
root -> count++;
}
void BST::inorderPrint (NodePtr root) const
{
if (root != NULL)
{
inorderPrint (root -> left);
cout << root -> word << "\t";
cout << root -> count;
inorderPrint (root -> right);
}
else
cout << endl;
}
bool BST::findNode (NodePtr root, char* word) const
{
if (root == NULL)
return false;
else
{
int k = compareVP (root -> word, word);
if (k == 0)
return true;
else if (k > 0)
return findNode (root -> left, word);
else
return findNode (root -> right, word);
}
}

Related

strdup for converting const char* to char*

I have designed for Huffman tree convert binary code with shorter bin code. In main if you call a Binary tree.init(q), then the tree would come out with key: frequency and value: bin code. The problem is converting const char* with char*. I've looked at some codes, and here I converted it by using strdup. Sometimes works fine but sometimes doesn't work. so I checked out the parameter for the function. Is there wrong in calling strdup or maybe others?
#pragma once
#include <stdio.h>
#include <queue>
#include <iostream>
#include "pch.h"
#include <string.h>
#include <string>
#define _CRT_SECURE_NO_WARNINGS
//this is a header file
using namespace std;
class Node
{
public:
//key : frequency, value : code
int f;
char* code;
Node* left;
Node* right;
int getFrequency()
{
return f;
}
char* getCode()
{
return code;
}
void init(int frequency, char* codestring)
{
f = frequency;
code = codestring;
}
Node* getLeft() {
return left;
}
Node* getRight()
{
return right;
}
void setLeft(Node* L)
{
left = L;
}
void setRight(Node* R)
{
right = R;
}
void setFrequency(int frequency)
{
f = frequency;
}
void setCode(char* string)
{
code = string;
}
};
class BinaryTree
{
public:
typedef priority_queue<int, vector<int>, greater<int>> pq;
pq q;
Node* proot;
int sizeofqueue;
void init(pq PriorityQueue)
{
q = PriorityQueue;
sizeofqueue = q.size();
N = 0;
int comparetimes = q.size() - 1;
for (int i = 0; i < comparetimes; i++)
{
if (i == 0)
{
put_first_two_nodes();
}
else
{
if (proot->getFrequency() <= q.top())
{
put_right_node();
}
else if (proot->getFrequency() > q.top())
{
put_left_node();
}
q.pop();
}
}
}
void put_first_two_nodes()
{
Node* pleft = new Node();
(*pleft).setFrequency(q.top());
(*pleft).setCode("0");
q.pop();
Node* pright = new Node();
(*pright).setFrequency(q.top());
(*pright).setCode("1");
put(pleft, pright);
q.pop();
}
void put_right_node()
{
Node* pright = new Node();
pright->setFrequency(q.top());
pright->setCode("1");
put(proot, pright);
appendcode(0);
}
void appendcode(int prefix)
{
string pre;
if (prefix == 1) pre = "1";
else pre = "0";
Node* targetNode = proot->getRight();
char* rcode = targetNode->getRight()->getCode();
char* lcode = targetNode->getLeft()->getCode();
string lefts = pre;
string rights = pre;
lefts.append(lcode);
rights.append(rcode);
char* leftstring = strdup(lefts.c_str());
char* rightstring = strdup(rights.c_str());
targetNode->getLeft()->setCode(leftstring);
targetNode->getRight()->setCode(rightstring);
free(leftstring);
free(rightstring);
}
void put_left_node()
{
Node* pleft = new Node();
pleft->setFrequency(q.top());
pleft->setCode("0");
put(pleft, proot);
appendcode(1);
}
char* get(int k)
{
return getItem(*proot, k);
}
char* getItem(Node root, int k)
{
//if there's no node
if (&root == nullptr) return "";
//if f or root > k, search left sibling
if (root.getFrequency() > k) return getItem(*(root.getLeft()), k);
//else, search right sibling
else if (root.getFrequency() < k) return getItem(*(root.getRight()), k);
//get it
else return root.getCode();
}
void put(Node* left, Node* right)
{
put_item(left,right);
}
void put_item(Node* left, Node* right)
{
//make new node that has sibling with left and right
Node* newnode = new Node();
newnode->setLeft(left);
newnode->setRight(right);
//exchange the new node and root without losing data
Node* temp;
temp = proot;
proot = newnode;
newnode = temp;
//proot's frequency : left f + right f
(*proot).setFrequency((*left).getFrequency() + (*right).getFrequency());
}
void printpost()
{
postorder(proot);
}
void postorder(Node* root)
{
if (root != nullptr)
{
if (root->getLeft() != nullptr) postorder(root->getLeft());
if (root->getRight() != nullptr) postorder(root->getRight());
printf("%d : %s ",root->getFrequency(), root->getCode());
}
}
private:
int N;
Node root;
};
You shouldn't use const char* and char* at all in c++ (unless when sometimes dealing with legacy or foreign interfaces).
Switch up your code to use eg. std::string or std::string_view (c++17) instead (string_view requires a bit more understanding to handle correctly and is const so to speak - so I would stick to string off the bat). Pass std::string by reference or by const reference where neccesary. The overhead of std::string is for most programs negliable.

How to count the occurence of each word in multiple text files

I want to count the occurence of each word in a bunch of texts.
I'm able to count each word and its occurence in one text ( I insert each word in the text in the binary tree and increment it by one whenver I find it again in the text) but I can't count each word in all texts.
Silly example:
text 1: hello adam, my name is adam I want to be happy.
text 2: hello sam, where is he from ?
(each word occurence in one text) Tree1: adam,2 hello,1 my,1 name,1 is,1 I,1 want,1 to,1 be,1 happy,1
(each word occurence in all texts) Tree2: hello,2 adam,1 sam,1 where,1 is,2 ...
Can someone explain to me what can I do ? or help me make an algorithm that does this?
My files:
Node.hpp
class Node{
private:
Node *left; //left child
Node *right; //right child
std::string num;
public:
int data; //number
Node(); //constructor
void setData(string num, int data); //sets number in node
string getData(); //return numbers from node
int &getOcc();
void setLeft(Node *l); //sets left child pointer
Node* &getLeft(); //returns left child pointer
void setRight(Node *r); //sets right child pointer
Node* &getRight(); //return right child pointer
};
Node.cpp
Node::Node(){
this->left = NULL;
this->right = NULL;
}
void Node::setData(string num, int data){
this->num = num;
this->data = data;
}
string Node::getData(){
return this->num;
}
int &Node::getOcc(){
return this->data;
}
void Node::setLeft(Node *l){
this->left = l;
}
Node* &Node::getLeft(){
return this->left;
}
void Node::setRight(Node *r){
this->right = r;
}
Node* &Node::getRight(){
return this->right;
}
BST.hpp
//BST class
class BST{
private:
Node * root; //root node pointer
public:
BST(); //constructor
~BST(); //destructor
void Insert(string num, int data); //Inserts new number in tree
void InsertIDF(string num, int data); //Inserts new number in tree
bool find(string num); //finds whether a number is present in tree
void min(); //find and print minimum number in the tree
void max(); //find and print maximum number in the tree
void save_file(string filename); //save the tree to file
void Delete(string num); //deletes a number from tree
void LoadFromFile(string filename); //loads numbers from file to tree
void Print(); //print tree to stdout
//private functions used as helper functions in the public operations
private:
void printHelper(Node *root);
bool findHelper(Node *root,string num);
void InsertHelper(Node * &current, string num, int data);
void InsertHelperIDF(Node * &current, string num, int data);
void findMinHelper(Node* current);
void findMaxHelper(Node * current);
void saveHelper(ofstream &fout, Node* current);
Node* DeleteHelper(Node *current, string num);
Node * findMaximum(Node * n);
void clear(Node *currnt);
};
BST.cpp
BST::BST(){
this->root = NULL; //root is NULL in the start
}
BST::~BST(){
clear(root); //delete all nodes
}
void BST::clear(Node* current){
if(current == NULL)
return;
clear(current->getLeft()); //clear left subtree
clear(current->getRight()); //clear right subtree
delete current; //delete this node
}
void BST::Insert(string num, int data){
InsertHelper(root,num,data); //call helper to insert
}
void BST::InsertHelper( Node * &current, string num, int data ){
if ( current == nullptr ){
// create new node to be inserted
current = new Node();
current->setData( num, data );
current->setLeft( nullptr );
current->setRight( nullptr );
} else if ( num < current->getData() ){
InsertHelper( current->getLeft(), num, data );
} else if ( current->getData() < num ){
InsertHelper( current->getRight(), num, data );
} else {
int h = current->getOcc();
h++;
current->setData(num, h);
}
}
void BST::InsertIDF(string num, int data){
InsertHelperIDF(root,num,data); //call helper to insert
}
void BST::InsertHelperIDF( Node * &current, string num, int data){
if ( current == nullptr ){
// create new node to be inserted
current = new Node();
current->setData( num, data );
current->setLeft( nullptr );
current->setRight( nullptr );
} else if ( num < current->getData() ){
InsertHelperIDF( current->getLeft(), num, data );
} else if ( current->getData() < num ){
InsertHelperIDF( current->getRight(), num, data );
}
}
void BST::min(){
findMinHelper(root);
}
void BST::findMinHelper(Node* current){
if(current == NULL)
return;
if(current->getLeft() == NULL) //if no node at right
cout<<current->getData(); //current has min data
else
findMinHelper(current->getLeft()); //check on left subtree
}
void BST::max(){
findMaxHelper(root);
}
void BST::findMaxHelper(Node * current){
if(current == NULL)
return;
if(current->getRight() == NULL) //if no node at right
cout<<current->getData(); //current node has max data
else
findMaxHelper(current->getRight()); //check on right subtree
}
void BST::Print(){
printHelper(root);
}
void BST::printHelper(Node *current){
if(current == NULL) //stop if NULL
return;
printHelper(current->getLeft()); //print left tree
cout<<current->getData() << " " << current->getOcc() << " "; //print current node data
printHelper(current->getRight()); //print right tree
}
void BST::Delete(string num){
root = DeleteHelper(root,num);
}
Node* BST::DeleteHelper(Node *current, string num){
if(current == NULL)
return NULL;
Node *tobeReturned;
if (current->getData() == num) { //if key is found
if (current->getLeft() == NULL) { //no node at left
tobeReturned = current->getRight();
delete current;
return tobeReturned; //right subtree should replace this node
} else if (current->getRight() == NULL) {
tobeReturned = current->getLeft();
delete current;
return tobeReturned;
} else {
//find maximum node in the left subtree
Node * maxnode = findMaximum(current->getLeft());
//copy values from max node to this node
// current->setData(maxnode->getData());
//delete the max node
current->setLeft(DeleteHelper(current->getLeft(), num));
}
cout<<"Deleted!!!";
} else { //not found
if (num < current->getData()) {
current->setLeft(DeleteHelper(current->getLeft(),num));
} else {
current->setRight(DeleteHelper(current->getRight(), num));
}
}
return current;
}
Node* BST::findMaximum(Node * n){
if(n->getRight() == NULL) //if no node at right, current is maximum
return n;
return findMaximum(n->getRight()); //find in right subtree
}
this is my main.cpp
int x = 0;
// go through each story
for( Histoire * histoire : * histoires ) {
// go through each sentence
for( Phrase p : * histoire ) {
// go through each word
for ( Phrase w : p ){
std::stringstream sstream;
sstream << w;
std::string s = sstream.str();
tree.Insert(s , 1); // here i insert each word in a tree and count its occurence in one text
}
// treeIDF.Insert(t,1);
};
Well it indeed seems like a homework :)
You sure binary tree is appropriate data structure for such problem? As suggested in comments, best would be to simply use std::map.
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>
void processFile(const std::string &filename,
std::map<std::string, int> &words_count) {
std::string word;
std::ifstream load_file;
load_file.open(filename.c_str(), std::ifstream::in);
while (load_file >> word) {
if (words_count.find(word) == words_count.end()) {
words_count[word] = 1;
} else {
words_count[word]++;
}
}
}
int main() {
const std::vector<std::string> files_to_process{"text1.txt", "text2.txt"};
std::map<std::string, int> words_count{};
for (const auto &file : files_to_process) {
processFile(file, words_count);
}
for (const auto &w : words_count) {
std::cout << w.first << " " << w.second << std::endl;
}
}
This has to be refined, though - like get rid of special characters, pack it into class etc. If you can't use STL (for whatever reason), simply create a key-value structure yourself and implement some search.

difficulty inserting into binary search tree

I am currently learning C++ and have been researching BST. I took upon myself a task within a workbook but have been struggling to finish the implementation.
I am not allowed to change the header file or any of the function definitions but I am allowed to add helpers.
I have attempted adding some helpers, but whenever I run the test file, no words are inserted into the tree.
I was hoping someone would be able to help me or give me guidance on finishing the implementation.
Any help on the other functions would be greatly appreciated!
My Header File:
#pragma once
#include <iostream>
#include <string>
// Node of the tree
struct Node
{
std::string data;
Node *left = nullptr;
Node *right = nullptr;
};
class BST
{
private:
Node *root = nullptr;
public:
BST();
BST(std::string word);
BST(const BST &rhs);
~BST();
void insert(std::string word);
void remove(std::string word);
bool exists(std::string word) const;
std::string inorder() const;
std::string preorder() const;
std::string postorder() const;
bool operator==(const BST &other) const;
bool operator!=(const BST &other) const;
};
My BST file:
#include "bst.h"
#include <iostream>
#include <string>
using namespace std;
string HelperInsert(Node **root, std::string word)
{
if (*root == nullptr)
{
// Create new node
*root = new Node;
// Set new value
(*root)->data = word;
// Set branches to nullptr
(*root)->left = nullptr;
(*root)->right = nullptr;
}
else
if (word < (*root)->data)
{
HelperInsert(&(*root)->left, word);
}
else
{
if (word > (*root)->data)
{
HelperInsert(&(*root)->right, word);
}
}
}
void HelperExists(Node *root, string word)
{
Node *temp = new Node;
temp = root;
// Run the loop untill temp points to a NULL pointer.
while(temp != NULL)
{
if(temp->data == word)
{
cout<<"True "<<endl;
}
// Shift pointer to left child.
else if(temp->data > word)
temp = temp->left;
// Shift pointer to right child.
else
temp = temp->right;
}
cout<<"\n False";
return;
}
string Helpwr(Node *root)
{
if(root == nullptr)
{
return "";
}
else
{
return inorderHelper(root->left)
+ root->data + " "
+ inorderHelper(root->right);
}
}
void HelperPreOrder(Node *root)
{
if ( root !=nullptr)
{
cout << root->data << " ";
HelperPreOrder(root->left);
HelperPreOrder(root->right);
}
}
void HelperPostorder(Node *root)
{
if (root!=nullptr)
{
HelperPostorder(root->left);
HelperPostorder(root->right);
cout << root->data<< endl;
return;
}
}
BST::BST()
{
root= nullptr;
}
// Creates a binary tree by copying an existing tree
BST::BST(const BST &rhs)
{
}
void BST::insert(string word)
{
HelperInsert(*root, word);
}
void BST::remove(string word)
{
}
bool BST::exists(string word) const
{
HelperExists(root, word);
return true;
}
std::string BST::inorder() const
{
string res = inorderHelper(root);
int len = res.length();
if(len >= 1 && res[len -1] == ' ')
{
res.pop_back();
}
return res;
}
std::string BST::preorder() const
{
HelperPreOrder(root);
return std::string("");
}
std::string BST::postorder() const
{
HelperPostorder(root);
return std::string("");
}
bool BST::operator==(const BST &other) const
{
return true;
}
bool BST::operator!=(const BST &other) const
{
return true;
}
My test file:
tree = new BinarySearchTree();
// Test 3 - insertion check
tree->insert("fish");
tree->insert("aardvark");
tree->insert("zeebra");
str = tree->inorder();
if (str != string("aardvark fish zeebra"))
cerr << "test 3 failed" << endl;
else
cout << "Test 3 passed" << endl;
// Test 4 - exists check
if (tree->exists("zeebra") && tree->exists("fish") && !tree->exists("bird") && !tree->exists("snake"))
cout << "Test 4 passed" << endl;
else
cerr << "test 4 failed" << endl;
Seems like an issue of not storing the string words correctly:
your insert method is as follows:
void insert(std::string word);
Which means a value of the string is passed, not a reference.
In order to store the string, you'll have to create a copy of the string and store it in memory:
string HelperInsert(Node **root, std::string word)
{
if (*root == nullptr)
{
// Create new node
*root = new Node;
// Set new value
(*root).data = new std:string(word); // note the setting of a string pointer here!
// Set branches to nullptr
(*root)->left = nullptr;
(*root)->right = nullptr;
}
else
if (word < (*root)->data)
{
HelperInsert(&(*root)->left, word);
}
else
{
if (word > (*root)->data)
{
HelperInsert(&(*root)->right, word);
}
}
}
Do not forget to delete the string when removing nodes, in order to prevent mempory leaks.
Good luck!

Issues printing binary tree using breadth-first traversal in C++?

I'm writing a program that converts an expression in prefix notation to an expression tree. I'm having trouble getting the correct problem and I believe something is wrong with my print function which uses breadth first traversal. For example, when I input +-*1234, I get the output below. However, the 1 and the 2 should be the first two nodes in Depth 3. Could anybody point me in the right direction or explain what is happening?
Output:
Enter a prefix expression: +-*1234
Depth 0: +
Depth 1: - 4
Depth 2: * 3 1 2
Depth 3: [Empty][Empty][Empty][Empty][Empty][Empty][Empty][Empty]
My program:
#include <iostream> // For cout, cin
#include <cctype> // For isdigit
#include <queue> // For queue, push, pop, front
#include <algorithm> // For max
using namespace std;
class node {
public:
// CONSTRUCTOR
node(char data);
char data;
node *left, *right;
};
node::node(char data)
{
this -> data = data;
this -> left = NULL;
this -> right = NULL;
}
class next_node {
public:
// CONSTRUCTOR
next_node(node *tree_node);
node *tree_node;
next_node *next;
};
next_node::next_node(node *tree_node)
{
this->tree_node = tree_node;
next = NULL;
}
class tree {
public:
// CONSTRUCTOR
tree() { root = NULL; }
// Member Functions
void add_node(node *ptr);
void insert(char data);
void build(string prefix);
void print();
int get_height(node *ptr);
int double_num(int n);
bool isOperator(char sym);
node *remove_node()
{
if (root != NULL) {
node *ptr = root -> tree_node;
root = root -> next;
return ptr;
}
}
node *get_root()
{
return (root -> tree_node);
}
private:
next_node *root;
};
void tree::add_node(node *ptr)
{
if (root == NULL) root = new next_node(ptr);
else {
next_node *new_ptr = new next_node(ptr);
new_ptr -> next = root;
root = new_ptr;
}
}
void tree::insert(char data)
{
// If number
if(isdigit(data)) {
node *new_ptr = new node(data);
add_node(new_ptr);
// If operator
} else if (isOperator(data)) {
node *new_ptr = new node(data);
new_ptr -> left = remove_node();
new_ptr -> right = remove_node();
add_node(new_ptr);
}
}
void tree::build(string prefix)
{
// Scan from right to left
for (int i = prefix.length() - 1; i >= 0 ; i--) {
insert(prefix[i]);
}
}
void tree::print()
{
queue<node*> values;
node * root_ptr = get_root();
queue<char> line;
if (root_ptr) values.push(root_ptr);
else {
values.push(NULL);
}
while (!values.empty())
{
node * current_node = values.front();
values.pop();
line.push(current_node -> data);
if (current_node -> left) {
values.push(current_node -> left);
}
if (current_node -> right) {
values.push(current_node -> right);
}
}
for(int i=0; i < get_height(root_ptr); i++) {
cout << "Depth " << i << ": ";
for(int j=0; j < double_num(i); j++) {
if (!line.empty()) {
if (line.front() == NULL) {
cout<< "Empty";
} else {
cout << line.front() << " ";
line.pop();
}
} else if (line.empty()) {
cout << "[Empty]";
}
}
cout << "\n";
}
}
int tree::get_height(node *ptr) {
if(ptr == NULL ) return 0;
else {
return (1 + max(get_height(ptr -> left),
get_height(ptr -> right)));
}
}
int tree::double_num(int n){
if (n == 0) {
return 1;
} else {
return 2 * double_num(n - 1);
}
}
bool tree::isOperator(char sym)
{
return ( sym == '+' ||
sym == '-' ||
sym == '*' ||
sym == '/' ||
sym == '^' ||
sym == '(' ||
sym == ')' );
}
int main()
{
string user_input;
tree expr_tree;
cout << "Enter a prefix expression: ";
cin >> user_input;
// Build binary tree and print result
expr_tree.build(user_input);
expr_tree.print();
return 0;
}`

Strange value on node deletion in AVL tree

Made an AVL tree and everything worked well until I tested it with a larger amount of inserts. Upon deletion of a node with two children the data field within the node that is "moved" gets a strange value. Wich I've learned is some undefined behavior in c++. I don't have a clue on how to go about it. What am I missing?
AVL_Tree.cpp
#include "AVL_Tree.h"
#include "stddef.h"
#include <stdexcept>
#include <iostream>
#include <algorithm>
/*
* Constructor for TreeNode
*/
AVL_Tree::TreeNode::TreeNode(const int& data)
: data(data), height(1), leftChild(NULL), rightChild(NULL){};
void AVL_Tree::TreeNode::printNodeValue()
{
std::cout << data << "\n";
}
void AVL_Tree::TreeNode::printTree(bool isRight, const std::string& indent)
{
if(rightChild != NULL)
{
rightChild->printTree(true, indent + (isRight ? " " : " | "));
}
std::cout << indent;
if(isRight)
{
std::cout << " /";
}
else
{
std::cout << " \\";
}
std::cout << "----- ";
printNodeValue();
if(leftChild != NULL)
{
leftChild->printTree(false, indent + (isRight ? " | " : " "));
}
}
void AVL_Tree::TreeNode::printTree()
{
if(rightChild != NULL)
{
rightChild->printTree(true, "");
}
printNodeValue();
if(leftChild != NULL)
{
leftChild->printTree(false, "");
}
}
/*
* Constructor for the AVL_Tree
*/
AVL_Tree::AVL_Tree()
{
this->root = NULL;
this->size = 0;
}
/**
* Destructor
*/
AVL_Tree::~AVL_Tree()
{
destruct(this->root);
}
/**
* Deletes TreeNode objects recursively
*/
void AVL_Tree::destruct(TreeNode* root)
{
if(root != NULL)
{
destruct(root->rightChild);
destruct(root->leftChild);
delete root;
root = NULL;
}
}
/**
*Removes specified node
*/
void AVL_Tree::deleteNode(const int& data)
{
TreeNode* temp = remove(this->root, data);
if(temp != NULL)
{
this->root = temp;
size--;
}
}
/**
*Adds new node to the tree by calling insert()
*/
void AVL_Tree::add(const int& data)
{
try
{
TreeNode* node = new TreeNode(data);
this->root = insert(this->root, node);
size++;
}
catch(std::string s)
{
std::cout << s << std::endl;
}
}
void AVL_Tree::print()
{
root->printTree();
}
/**
* Prints the tree in ascending order
*/
void AVL_Tree::inOrder(TreeNode* current)
{
if(current != NULL)
{
inOrder(current->leftChild);
std::cout << current->data << std::endl;
inOrder(current->rightChild);
}
}
/**
*Recursively traverse the tree to find the correct place for the new node and then
*returns the tree.
*/
AVL_Tree::TreeNode* AVL_Tree::insert(TreeNode* current, TreeNode* newNode)
{
if(current == NULL)
{
return newNode;
}
if(newNode->data < current->data)
{
current->leftChild = insert(current->leftChild, newNode);
}
else if(newNode->data > current->data)
{
current->rightChild = insert(current->rightChild, newNode);
}
else
{
throw std::string("Data already exist in tree");
}
//return current;
return balance(current);
}
/**
* Recursively finds the TreeNode that matches 'dataToRemove' and erase it from the tree then returns the new tree
*/
AVL_Tree::TreeNode* AVL_Tree::remove(TreeNode* current, const int& dataToRemove)
{
if(current == NULL)
{
return current;
}
if(dataToRemove < current->data)
{
current->leftChild = remove(current->leftChild, dataToRemove);
}
else if(dataToRemove > current->data)
{
current->rightChild = remove(current->rightChild, dataToRemove);
}
else //if(dataToRemove == current->data)
{
TreeNode* temp = NULL;
//No children
if(current->leftChild == NULL && current->rightChild == NULL)
{
delete current;
current = NULL;
}
//One child
else if(current->leftChild != NULL && current->rightChild == NULL)
{
temp = current->leftChild;
current->data = temp->data;
current->leftChild = remove(current->leftChild, temp->data);
}
else if(current->leftChild == NULL && current->rightChild != NULL)
{
temp = current->rightChild;
current->data = temp->data;
current->rightChild = remove(current->rightChild, temp->data);
}
//Two children
else if(current->leftChild != NULL && current->rightChild != NULL)
{
temp = findSuccessor(current->rightChild);
current->data = temp->data;
remove(current->rightChild, temp->data);
}
}
return balance(current);
}
/**
* Returns height of tree
*/
int AVL_Tree::height(TreeNode* current)
{
if(current == NULL)
{
return 0;
}
return current->height;
}
/**
* Returns the balance factor for the argument(TreeNode pointer)
*/
int AVL_Tree::getBalance(TreeNode* current)
{
if(current == NULL)
{
return 0;
}
return height(current->rightChild) - height(current->leftChild);
}
/**
* Sets the height of the specified TreeNode
*/
void AVL_Tree::fixHeight(TreeNode* current)
{
int hl = height(current->leftChild);
int hr = height(current->rightChild);
current->height = (hl > hr ? hl : hr) + 1;
}
/**
* Takes TreeNode pointer as arguement and balances the tree if it isn't NULL
*/
AVL_Tree::TreeNode* AVL_Tree::balance(TreeNode* current)
{
if (current != NULL) {
fixHeight(current);
if(getBalance(current) == 2)
{
if(getBalance(current->rightChild) < 0)
{
current->rightChild = rotateRight(current->rightChild);
}
return rotateLeft(current);
}
if(getBalance(current) == -2)
{
if(getBalance(current->leftChild) > 0)
{
current->leftChild = rotateLeft(current->leftChild);
}
return rotateRight(current);
}
return current;
} else {
return NULL;
}
}
/**
* Preforms a left rotation
* Returns the rotated subtree
*/
AVL_Tree::TreeNode* AVL_Tree::rotateLeft(TreeNode* current)
{
TreeNode* right = current->rightChild;
current->rightChild = right->leftChild;
right->leftChild = current;
fixHeight(current);
fixHeight(right);
return right;
}
/**
* Preforms a right rotation
*/
AVL_Tree::TreeNode* AVL_Tree::rotateRight(TreeNode* current)
{
TreeNode* left = current->leftChild;
current->leftChild = left->rightChild;
left->rightChild = current;
fixHeight(current);
fixHeight(left);
return left;
}
/**
* Takes TreeNode pointer as argument and return the "leftest"(smallest) node in the right subtree.
*/
AVL_Tree::TreeNode* AVL_Tree::findSuccessor(TreeNode* current)
{
while(current->leftChild != NULL)
{
current = current->leftChild;
}
return current;
}
AVL_Tree.h
#ifndef AVLTREE_H
#define AVLTREE_H
#include <string>
class AVL_Tree
{
private:
struct TreeNode
{
TreeNode(const int& data);
int data;
int height;
TreeNode* leftChild;
TreeNode* rightChild;
void printTree(bool isRight, const std::string& indent);
void printTree();
void printNodeValue();
};
int size;
TreeNode* root;
TreeNode* findSuccessor(TreeNode* current);
TreeNode* remove(TreeNode* current, const int& dataToRemove);
TreeNode* insert(TreeNode* current, TreeNode* newNode);
int height(TreeNode* current);
TreeNode* balance(TreeNode* current);
int getBalance(TreeNode* current);
TreeNode* rotateLeft(TreeNode* current);
TreeNode* rotateRight(TreeNode* current);
void fixHeight(TreeNode* current);
void destruct(TreeNode* root);
TreeNode* findMin(TreeNode* current);
TreeNode* removeMin(TreeNode* current);
public:
AVL_Tree();
~AVL_Tree();
void deleteNode(const int& data);
void add(const int& data);
void print();
void inOrder(TreeNode* current);
};
#endif
main.cpp
#include "AVL_Tree.h"
#include <stdlib.h>
#include <vector>
using std::vector;
int main()
{
AVL_Tree at;
vector<int> list;
for(int i = 0; i < 20; i++)
{
int x = rand() % 100;
list.push_back(x);
at.add(x);
}
at.print();
at.add(list[0]);
at.print();
for(int i = 19; i >= 18; i--)
{
at.deleteNode(list[i]);
}
at.print();
return 0;
}
Output
output
If the data already exist in your tree, your code throws an exception. The calling code is assigning a pointer to a non returning function.
this->root = insert(this->root, node);
Test your code with some hard coded values and make sure to test with a duplicate value.