Segmentation fault in UNIX but not Windows - c++

I'm trying to get my DFS code working in UNIX, but whenever I run it it gives me a segmentation fault, yet it works fine in Windows. The code is supposed to take in a string and sort it to reach some predefined goal state by moving around a single letter at a time. I don't have much experience in UNIX so I would really appreciate some insight into this issue. Thank you!
struct node
{
node* parent;
string key;
int cost;
int heuristicCost;
node()
{
parent = nullptr;
key = "key";
cost = 0;
heuristicCost = 0;
}
};
void BFS(string sortString)
{
// Create Queue
list<node*> queue;
list<string> explored;
// Add the initial case to the Queue
node *n = new node;
n->key = sortString;
queue.push_back(n);
int steps = 1;
while (!queue.empty())
{
// Print out the current node to be checked and the operation that was performed on it
for (int i = 0; i < (int)queue.front()->key.length(); i++)
{
if (queue.front()->key[i] == 'X')
{
if (steps == 1)
{
cout << queue.front()->key << endl;
steps++;
}
else
{
cout << "move " << i << " " << queue.front()->key << endl;
steps++;
}
}
}
// Check if the goal state is reached
if (GoalTest(queue.front()->key))
{
cout << "Final Result for BFS:" << endl;
node* currentNode = queue.front();
list<node*> path;
while (currentNode->parent != nullptr) {
path.push_front(currentNode);
currentNode = currentNode->parent;
}
int i = 1;
while((int)path.size() >= 1)
{
cout << "Step " << i << ": " << path.front()->key << endl;
i++;
path.pop_front();
}
return;
}
else
{
// If goal state is not reached, add new nodes to the frontier
explored.push_back(queue.front()->key);
for (int i = 0; i < (int)queue.front()->key.length(); i++)
{
// Do a move action on the next node to be enqueued, if node is already in explored list, skip it
string key = Move(i, queue.front()->key);
bool found = (find(explored.begin(), explored.end(), key) != explored.end());
if (found)
{
continue;
}
else
{
node *newNode = new node;
newNode->key = key;
newNode->parent = queue.front();
queue.push_back(newNode);
}
}
// Remove the first node of the queue
queue.pop_front();
bool found = (find(explored.begin(), explored.end(), queue.front()->key) != explored.end());
while (found)
{
queue.pop_front();
found = (find(explored.begin(), explored.end(), queue.front()->key) != explored.end());
}
}
}
// If loop exits normally, search failed
cout << "Failure!" << endl;
return;
}

Related

Why is it that, when I try to shift all of the strings into my custom made Queue template and try to print, it only prints the last in the queue?

Truth be told, this is an assignment that I'm trying to complete. The basic thing that we have to do is create a Stack and Queue without STL and then create Stack and Queue with STL. I pretty much finished up creating my custom Stack, and it works perfectly. However, with Queue, whenever I try to shift strings into it and print it out, the console will only print out the string that was the last to be shifted. On top of that, whenever I try to unshift the last thing entered into the Queue with the code that I have, I end up getting a read access violation, that of which I am completely stumped on resolving.
If you don't mind, can you look through my code and help me understand what I did that is causing this error and the last entry in my Queue to be the only one printed out? Thanks in advance.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
struct Node {
//create a node struct
string data;
Node *next;
};
class Stack {
public:
Stack();
~Stack();
void push(string a);
string pop();
string toString();
bool isEmpty();
private:
Node * top;
};
class Queue {
public:
Queue();
~Queue();
void shift(string a);
string unshift();
string toString();
bool isEmpty();
private:
Node * top;
Node * bottom;
int count;
};
Stack::Stack() {
//initializes stack to be empty
top = NULL;
}
Queue::Queue() {
//initializes stack to be empty
top = NULL;
}
Stack::~Stack() {
//deconstructor to delete all of the dynamic variable
if (top == NULL) {
cout << "Nothing to clean up" << endl;
}
else {
cout << "Should be deleting..." << endl;
}
}
Queue::~Queue() {
//deconstructor to delete all of the dynamic variable
if (bottom == NULL) {
cout << "Nothing to clean up" << endl;
}
else {
cout << "Should be deleting..." << endl;
}
}
void Stack::push(string a) {
//Need a new node to store d in
Node *temp = new Node;
temp->data = a;
temp->next = top;//point the new node's next to the old top of the stack
top = temp;//point top to the new top of the stack
}
void Queue::shift(string a) {
//Need a new node to store d in
Node *temp = new Node;
temp->data = a;
temp->next = NULL;//point the new node's next to the old top of the stack
if (isEmpty()) {
top = temp;
}
else {
top->next = temp;
count++;
}
top = temp;//point top to the new top of the stack
}
string Stack::pop() {
if (!isEmpty()) {
string value = top->data;
Node *oldtop = top;
top = oldtop->next;
delete oldtop;
return value;
}
else {
cout << "You can't pop from an empty stack!" << endl;
exit(1);
}
}
string Queue::unshift() {
if (isEmpty()) {
cout << "You can't unshift an empty Queue!" << endl;
exit(1);
}
else{
Node *oldbot = top;
if (top == bottom) {
top = NULL;
bottom = NULL;
}
else {
string value = top->data;
}
delete oldbot;
count--;
}
}
string Stack::toString() {
string result = "top ->";
if (isEmpty()) {
result = result + "NULL";
return result;
}
else {
Node *current = top;
while (current != NULL) {
result = result + current->data + "->";
current = current->next;
}
result = result + "(END)";
return result;
}
}
string Queue::toString() {
string result = "top ->";
if (isEmpty()) {
result = result + "NULL";
return result;
}
else {
Node *current =top;
while (current != NULL) {
result = result + current->data + "->";
current = current->next;
}
result = result + "(END)";
return result;
}
}
bool Stack::isEmpty() {
return(top == NULL);
}
bool Queue::isEmpty() {
return(top == NULL);
}
int main()
{
Stack *s = new Stack();
cout << "Output when empty: " << endl << s->toString() << endl;
s->push("Cheeseburger");
s->push("Pizza");
s->push("Large coffee");
s->pop();
cout << "Output when not empty: " << endl << s->toString() << endl;
delete s;
cin.get();
Queue *b = new Queue();
cout << "Output when empty: " << endl << b->toString() << endl;
b->shift("Cheeseburger");
b->shift("Pizza");
b->shift("Large coffee");
cout << "Output when not empty: " << endl << b->toString() << endl;
b->unshift();
delete b;
cin.get();
}
You have to comment below statement in Queue::shift method -
top = temp;

AVL Tree implementation c++

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);
}

c++ Stuck making an binary tree implementation with an array and lists

I am working on writing a list of children binary tree implementation. In my code I have an array of lists. Each list contains a node followed by its children on the tree. I finished writing the code and everything compiled, but I keep getting a segmentation fault error and I cannot figure out why. I have been attempting to debug and figure out where my code messes up. I know that there is an issue with the FIRST function. It causes a segmentation fault. Also, when I try to print just one of the lists of the array, it prints everything. I have been stuck on this for a very long time now and would like some help. Can anyone offer suggestions as to why the FIRST and PRINT functions are not working? Maybe there is a large error that I just cannot see.
My code is as follows:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <array>
#include <string.h>
using namespace std;
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
void ADD(char n);
node* CREATE(char n);
void BEGIN(char n);
char FIRST();
char END();
char NEXT(char n);
char PREVIOUS(char n);
int LOCATE(char n);
void EMPTY();
void PRINT();
list()
{
start = NULL;
}
};
char PARENT(const char n, list tree[], int length)
{
int i=0;
list l;
for (i; i<length; i++)
{
l = tree[i];
if (n != l.FIRST())
{
if (l.LOCATE(n)>0)
return l.FIRST();
}
}
}
char LEFTMOST_CHILD(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if (l.FIRST() == n)
return l.NEXT(n);
}
}
char RIGHT_SIBLING(char n, list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
if(n != l.FIRST())
{
if (l.LOCATE(n) > 0)
{
return l.NEXT(n);
}
}
}
}
char ROOT(list tree[]) //assumes array is in order, root is first item
{
list l;
l = tree[0];
cout << "Assigned tree to l" << endl;
return l.FIRST();
}
void MAKENULL(list tree[], int length)
{
int i;
list l;
for (i=0; i<length; i++)
{
l = tree[i];
l.EMPTY();
}
}
void list::PRINT()
{
struct node *temp;
if (start == NULL)
{
cout << "The list is empty" << endl;
return;
}
temp = start;
cout << "The list is: " << endl;
while (temp != NULL)
{
cout << temp->element << "->" ;
temp = temp->next;
}
cout << "NULL" << endl << endl;
}
void list::EMPTY()
{
struct node *s, *n;
s = start;
while (s != NULL)
{
n = s->next;
free(s);
s = n;
}
start = NULL;
}
int list::LOCATE(char n)
{
int pos = 0;
bool flag = false;
struct node *s;
s = start;
while (s != NULL)
{
pos++;
if (s->element == n)
{
flag == true;
return pos;
}
s = s->next;
}
if (!flag)
return -1;
}
void list::ADD(char n)
{
struct node *temp, *s;
temp = CREATE(n);
s = start;
while (s->next != NULL)
s = s->next;
temp->next = NULL;
s->next = temp;
}
node *list::CREATE(char n)
{
struct node *temp;
temp = new(struct node);
temp->element = n;
temp->next = NULL;
return temp;
}
void list::BEGIN(char n)
{
struct node *temp, *p;
temp = CREATE(n);
if (start == NULL)
{
start = temp;
start->next = NULL;
}
}
char list::FIRST()
{
char n;
struct node *s;
s = start;
cout << "s = start" << endl;
n = s->element;
cout << "n" << endl;
return n;
}
char list::END()
{
struct node *s;
s = start;
int n;
while (s != NULL)
{
n = s->element;
s = s->next;
}
return n;
}
char list::NEXT(char n)
{
char next;
struct node *s;
s = start;
while (s != NULL)
{
if (s->element == n)
break;
s = s->next;
}
s = s->next;
next = s->element;
return next;
}
char list::PREVIOUS(char n)
{
char previous;
struct node *s;
s = start;
while (s != NULL)
{
previous = s->element;
s = s->next;
if (s->element == n)
break;
}
return previous;
}
main()
{
list a,b,c,d,e,f,g,h,i,j,k,l,m,n;
a.BEGIN('A');
b.BEGIN('B');
c.BEGIN('C');
d.BEGIN('D');
e.BEGIN('E');
f.BEGIN('F');
g.BEGIN('G');
h.BEGIN('H');
i.BEGIN('I');
j.BEGIN('J');
k.BEGIN('K');
l.BEGIN('L');
m.BEGIN('M');
n.BEGIN('N');
a.ADD('B');
a.ADD('C');
b.ADD('D');
b.ADD('E');
e.ADD('I');
i.ADD('M');
i.ADD('N');
c.ADD('F');
c.ADD('G');
c.ADD('H');
g.ADD('J');
g.ADD('K');
h.ADD('L');
a.PRINT();
list tree[] = {a,b,c,d,e,f,g,h,i,j,k,l,m,n};
int length = sizeof(tree)/sizeof(char);
char root = ROOT(tree);
cout << "Found root" << endl;
char parent = PARENT('G', tree, length);
cout << "Found Parent" << endl;
char leftChild = LEFTMOST_CHILD('C', tree, length);
cout << "found left child" << endl;
char rightSibling = RIGHT_SIBLING('D', tree, length);
cout << "found right sibling" << endl;
cout << "The root of the tree is: ";
cout << root << endl;
cout << "The parent of G is: ";
cout << parent << endl;
cout << "The leftmost child of C is" ;
cout << leftChild << endl;
cout << "The right sibling of D is: " ;
cout << rightSibling << endl;
}
Any help will be very appreciated. Thanks you!
The fundamental problem is that you have written a lot of code before testing any of it. When you write code, start with something small and simple that works perfectly, add complexity a little at a time, test at every step, and never add to code that doesn't work.
The specific problem (or at least one fatal problem) is here:
struct node
{
char element;
struct node *next;
}*start;
class list
{
public:
//...
list()
{
start = NULL;
}
};
The variable start is a global variable. The class list has no member variables, but uses the global variable. It sets start to NULL every time a list is constructed, and every list messes with the same pointer. The function FIRST dereferences a pointer without checking whether the pointer is NULL, and when it is, you get Undefined Behavior.
It's not entirely clear what you intended, but you seem to misunderstand how variables work in C++.

C++ linked list values changing retroactively

EDIT: Solution Code included at the end.
I am trying to implement a linked list class that utilizes a node class as defined in the assignment. The below code block prints output as expected:
#include <iostream>
using namespace std;
// Node class as provided
class node {
void *info;
node *next;
public:
node (void *v) {info = v; next = 0; }
void put_next (node *n) {next = n;}
node *get_next ( ) {return next;}
void *get_info ( ) {return info;}
};
// Linked list class
class list {
//Start of the linked list
node *start;
public:
list (int v) {
start = new node (&v);
}
void insert (int value, int place=-1) {
node *temp = new node (&value);
if (place == 0) {
temp->put_next(start);
start = temp;
} else {
node *before = start;
for (int i = 1; before->get_next() != 0; i++) {
if (i == place) {
break;
}
before = before->get_next();
}
temp->put_next(before->get_next());
before->put_next(temp);
}
}
void remove(int place) {
if (place == 0) {
start = start->get_next();
} else {
node *curr = start;
for (int i = 1; curr != 0; i ++) {
if (i == place) {
curr->put_next(curr->get_next()->get_next());
break;
}
curr = curr->get_next();
}
}
}
void display() {
for (node *current = start; current != 0; current = current->get_next()) {
cout << *(static_cast<int*>(current->get_info())) << endl;
}
}
};
int main() {
list *tst = new list(10);
tst->display();
cout << "Prepending 9" << endl;
tst->insert(9,0);
tst->display();
cout << "Inserting 8" << endl;
tst->insert(8,1);
tst->display();
cout << "Prepending 7" << endl;
tst->insert(7,0);
tst->display();
tst->remove(0);
cout << "Removed the first element:" << endl;
tst->display();
cout << endl;
// cout << "Prepending 6" << endl;
// tst->insert(6,0);
// tst->display();
}
Creates this output:
10
Prepending 9
9
10
Inserting 8
9
8
10
Prepending 7
7
9
8
10
Removed the first element:
9
8
10
However, when I add this last statement to the end of the program flow in main:
tst->insert(6,0);
My output changes to this:
10
Prepending 9
9
10
Inserting 8
8
8
10
Prepending 7
7
7
7
10
Removed the first element:
134515798
134515798
10
What am I missing? How can adding a value later in execution change the output that happens before I even get to that point in the program flow?
I am using ideone.com as my IDE/to run the program, I've never had an issue before, but is that the issue?
Solution
#include <iostream>
using namespace std;
// Provided node class
class node {
void *info;
node *next;
public:
node (void *v) {info = v; next = 0; }
void put_next (node *n) {next = n;}
node *get_next ( ) {return next;}
void *get_info ( ) {return info;}
};
// List class template
template <class T>
class list {
node *start;
public:
list (T v) {
start = new node (&v);
}
// Insert method
void insert (T *value, int place=-1) {
node *temp = new node (value);
// If we're putting it at the beginning, then change the reference to start
if (place == 0) {
temp->put_next(start);
start = temp;
}
// We're inserting it somewhere other than the beginning, handle appropriately
else {
node *before = start;
// Loop to find preceeding node
for (int i = 1; before->get_next() != 0; i++) {
if (i == place) {
break;
}
before = before->get_next();
}
// Insert after preceeding node, and point at subsequent node
temp->put_next(before->get_next());
before->put_next(temp);
}
}
// Remove function
void remove(int place) {
// If we're removing hte beginning, then change start pointer
if (place == 0) {
start = start->get_next();
}
// Find node to remove
else {
node *curr = start;
for (int i = 1; curr != 0; i ++) {
if (i == place) {
// Cut target node out of list
curr->put_next(curr->get_next()->get_next());
break;
}
curr = curr->get_next();
}
}
}
// Print nodes
void display() {
for (node *current = start; current != 0; current = current->get_next()) {
cout << *(static_cast<T*>(current->get_info())) << endl;
}
cout << endl;
}
};
int main() {
int nine = 9;
int eight = 8;
int seven = 7;
int six = 6;
int five = 5;
cout << "Create list holding '10'" << endl;
list<int> *tst = new list<int>(10);
cout << "Prepending 9" << endl;
tst->insert(&nine,0);
cout << "Inserting 8 at 2nd place" << endl;
tst->insert(&eight,1);
cout << "Appending 7" << endl;
tst->insert(&seven);
cout << "Prepending 6" << endl;
tst->insert(&six,0);
cout << "Inserting 5 at 3rd place" << endl;
tst->insert(&five,2);
cout << "Show completed list:" << endl;
tst->display();
cout << "Removing the first element:" << endl;
tst->remove(0);
tst->display();
cout << "Removing the last element:" << endl;
tst->remove(4);
tst->display();
cout << "Removing the second element:" << endl;
tst->remove(1);
tst->display();
}
You have undefined behavior in your code, because you save pointers to local variables, variables that goes out of scope once the function returns.
The variable I'm talking about is the argument value inside the insert function, once the insert function returns that pointer is no longer valid.
The quick solution? Don't store pointers, store a list of integers. Or maybe make the list (and node) a templated class and store by value.
If you truly want a list that can contain anything, the consider using e.g. Boost any.

Level Order Traversal: Deleting a Subtree

#include <iostream>
using namespace std;
struct node {
int item;
node* l;
node* r;
node (int x) {
item = x;
l = 0;
r = 0;
}
node(int x, node* l, node* r) {
item = x;
this->l = l;
this->r = r;
}
};
typedef node* link;
class QUEUE {
private:
link* q;
int N;
int head;
int tail;
public:
QUEUE(int maxN) {
q = new link[maxN + 1];
N = maxN + 1;
head = N;
tail = 0;
}
int empty() const {
return head % N == tail;
}
void put(link item) {
q[tail++] = item;
tail = tail % N;
}
link get() {
head = head % N;
return q[head++];
}
};
link head = 0; // Initial head of the tree
link find(int x) {
if (head == 0) {
cout << "\nEmpty Tree\n";
return 0;
}
link temp = head;
// To find the node with the value x and return its link
QUEUE q(100);
q.put(temp);
while (!q.empty()) {
temp = q.get();
if (temp->item == x) {
return temp;
}
if (temp->l != 0) q.put(temp->l);
if (temp->r != 0) q.put(temp->r);
}
return 0;
}
void print(link temp) {
QUEUE q(100);
q.put(temp);
while (!q.empty()) {
temp = q.get();
cout << temp->item << ", ";
if (temp->l != 0) q.put(temp->l);
if (temp->r != 0) q.put(temp->r);
}
}
void deleteAll(link h) {
// This deletes the entire binary tree
QUEUE q(100);
q.put(h);
while (!q.empty()) {
h = q.get();
if (h->l != 0) q.put(h->l);
if (h->r != 0) q.put(h->r);
delete h;
}
}
int main() {
link temp = 0;
char c;
int n1, n2;
cout << "\n\nPlease enter the input instructions (X to exit program) : \n\n";
do {
cin >> c;
switch (c) {
case 'C': cin >> n1;
if (head == 0) {
head = new node(n1);
cout << "\nRoot node with item " << n1 << " has been created\n\n";
} else {
cout << "\nError: Tree is not empty\n\n";
}
break;
case 'L': cin >> n1 >> n2;
temp = find(n1);
if (temp != 0) {
if (temp->l == 0) {
temp->l = new node(n2);
cout << "\nNode with item " << n2 << " has been added\n\n";
}
else {
cout << "\nError: The specified node already has a left child\n\n";
}
}
else {
cout << "\nError: The specified node doesn't exist\n\n";
}
break;
case 'R': cin >> n1 >> n2;
temp = find(n1);
if (temp != 0) {
if (temp->r == 0) {
temp->r = new node(n2);
cout << "\nNode with item " << n2 << " has been added\n\n";
}
else {
cout << "\nError: The specified node already has a right child\n\n";
}
}
else {
cout << "\nError: The specified node doesn't exist\n\n";
}
break;
case 'P': cin >> n1;
temp = find(n1);
if (head != 0) {
cout << "\nLevel-order traversal of the entire tree: ";
print(temp);
}
else {
cout << "\nError: No elements to print\n\n";
}
break;
case 'D': cin >> n1;
temp = find(n1);
deleteAll(temp);
temp = 0;
break;
case 'X': cout << "\nExiting Program\n\n";
break;
default: cout << "\nInvalid input entered. Try again.\n\n";
}
} while (c != 'X');
system("pause");
return 0;
}
Sample Input:
C 9
L 9 8
R 9 6
L 8 3
R 8 5
R 6 2
L 3 4
L 4 10
L 5 1
R 5 11
L 1 12
R 1 7
It all works fine until I delete a subtree and print when it prints garbage value before crashing. Please help me figure out the bug because I've been trying in vain for hours now.
It all works fine until I delete a subtree and print when it prints garbage value before crashing. Please help me figure out the bug because I've been trying in vain for hours now.
Try the recursive function:
void Delete(link h)
{
if(h)
{
if(h->l) Delete(h->l);
if(h->r) Delete(h->r);
delete(h);
}
}
When you delete a node, you call deleteAll(temp) which deletes temp, but it doesn't remove the pointer value from the l or r of temp's parent node.
This leaves you with a invalid pointer, causing garbage printing and crashing.
Unfortunately, the way your find works currently, you don't know what the current temp node's parent is when you get around to checking its value.
One way to fix it is to have a different type of find (called something like remove) that looks in l and r at each iteration for the value and sets l or r to NULL before returning the pointer. You might have to have a special case for when the value is found in the root.
Edit (sample code added):
I am assuming you are not using recursion for some reason, so my code uses your existing queue based code. I only changed enough to get it working.
findAndUnlink find the node with the value given and "unlinks" it from the tree. It returns the node found, giving you a completely separate tree. Note: it is up to the caller to free up the returned tree, otherwise you will leak memory.
This is a drop in replacement for find in your existing code, as your existing code then calls deleteAll on the returned node.
link findAndUnlink(int x) {
if (head == 0) {
cout << "\nEmpty Tree\n";
return 0;
}
link temp = head;
if (temp->item == x) {
// remove whole tree
head = NULL;
return temp;
}
// To find the node with the value x and remove it from the tree and return its link
QUEUE q(100);
q.put(temp);
while (!q.empty()) {
temp = q.get();
if (temp->l != NULL) {
if (temp->l->item == x) {
link returnLink = temp->l;
temp->l = NULL;
return returnLink;
}
q.put(temp->l);
}
if (temp->r != NULL) {
if (temp->r->item == x) {
link returnLink = temp->r;
temp->r = NULL;
return returnLink;
}
q.put(temp->r);
}
}
return 0;
}