I am implementing an AVL tree and my search and insertion functions work properly, but I get a segmentation fault with my remove function. I have implemented a BST tree correctly before, so I know the issue is with the rebalancing of the tree rather than the initial deletion of a node.
Since my insertion operation works with the rebalancing, I also know the issue is not with the rotation functions themselves.
I have tried different strategies such as maintaining a balance factor at each node and have tried implementing other source code I have found online but I always end up with a segmentation fault and really cannot find where. I'd appreciate any help.
class AVL
{
public:
AVL();
Node* insert(int num);
Node* search(int num);
Node* remove(int num);
void print();
void comparisonPrint();
private:
int comparisonCount;
Node* root;
int max(int a, int b);
int getHeight(Node* t);
int getBalance(Node* t);
Node* insert(Node* &t, int num);
Node* rotateWithLeftChild(Node* t);
Node* rotateWithRightChild(Node* t);
Node* doubleRotateWithLeftChild(Node* t);
Node* doubleRotateWithRightChild(Node* t);
Node* search(Node* t, int num);
Node* removeMin(Node* parent, Node* node);
Node* remove(Node* &t, int num);
void print(Node* t);
//print
};
int AVL::max(int a, int b)
{
return (a > b)? a : b;
}
int AVL::getHeight(Node* t)
{
return (t == NULL) ? 0 : t->height;
}
int AVL::getBalance(Node* t)
{
if(t == NULL)
return 0;
return getHeight(t->leftChild) - getHeight(t->rightChild);
}
//helper function for remove - finds min
Node* AVL::removeMin(Node* parent, Node* node) //removes node, but does not delete - returns ptr instead
{
if(node != NULL)
{
if(node->leftChild != NULL) //go to leftmost child in right subtree
return removeMin(node, node->leftChild);
else //min val
{
parent->leftChild = node->rightChild;
return node;
}
}
else //subtree empty - incorrect use of function
return NULL;
}
Node* AVL::remove(Node* &t, int num)
{
cout << num;
if(t != NULL)
{
if(num > t->key)
{
comparisonCount++;
remove(t->rightChild, num);
}
else if(num < t->key)
{
comparisonCount++;
remove(t->leftChild, num);
}
else if(t->leftChild != NULL && t->rightChild != NULL)
{
comparisonCount++;
//2 children
Node* minRightSubtree = removeMin(t, t->rightChild);
t->key = minRightSubtree->key;
delete minRightSubtree;
}
else
{
comparisonCount++;
//0 or 1 child
Node* temp = t;
if(t->leftChild != NULL)
t = t->leftChild;
else if(t->rightChild != NULL)
t = t->rightChild;
delete temp;
}
//update height
t->height = max(getHeight(t->leftChild), getHeight(t->rightChild)) + 1;
int balance = getBalance(t);
if(balance > 1 && getBalance(t->leftChild) >= 0)
return rotateWithRightChild(t);
if(balance > 1 && getBalance(t->leftChild) < 0)
{
t->leftChild = rotateWithLeftChild(t->leftChild);
return rotateWithRightChild(t);
}
if(balance < -1 && getBalance(t->rightChild) <= 0)
return rotateWithLeftChild(t);
if(balance < -1 && getBalance(t->rightChild) > 0)
{
t->rightChild = rotateWithRightChild(t->rightChild);
return rotateWithLeftChild(t);
}
}
return t;
}
So I need the remove function to remove a specified node and rebalance the tree when necessary using the appropriate rotations. However, I keep getting a segmentation fault whenever I try to call the function in my main. Thanks.
There are two problems with your code. First is the removeMin function and the else if part in remove function when the node to be deleted has two children.
Basic aim of the removeMin function should be to find the inorder successor of the node to be deleted which is t in your case. Consider the case when t has 2 children (both leaf nodes) then your removeMin function will set t->leftChild as t->rightChild->rightChild which is NULL which is wrong. Also the restructuring of the tree should be done inside remove hence removeMin becomes:
Node* AVL::removeMin(Node* node) // returns inorder successor of 't'
{
if(node->left == NULL)
return node;
return removeMin(node->left);
}
Coming to remove function, we reset t->key with minRightSubtree->key and the node to be deleted now is minRightSubtree. But notice that the order of keys has changed in the chain from node t till node minRightSubtree. t->key is less than all the keys of nodes till before minRightSubtree. Hence you cannot just delete minRightSubtree, you have to call remove function on the node minRightSubtree which will take care of restructuring this chain. Also you can get a little help from the recursion stack to get the correct child for the current node t after deletion/rotation:
Node* AVL::remove(Node* &t, int num)
{
if (t == NULL)
return NULL;
if (num > t->key)
t->rightChild = remove(t->rightChild, num);
else if (num < t->key)
t->leftChild = remove(t->leftChild, num);
else if (t->leftChild != NULL && t->rightChild != NULL)
{
//2 children
Node* minRightSubtree = removeMin(t->rightChild);
t->key = minRightSubtree->key;
t->rightChild = remove(t->rightChild, minRightSubtree->key);
}
else
{
//0 or 1 child
Node* temp = t;
if (t->leftChild != NULL)
t = t->leftChild;
else if (t->rightChild != NULL)
t = t->rightChild;
if(temp == t)
t = NULL;
delete temp;
}
if (t == NULL) // this case was added since there is a possibility of deleting 't'
return NULL;
//update height
t->height = max(getHeight(t->leftChild), getHeight(t->rightChild)) + 1;
int balance = getBalance(t);
if (balance > 1 && getBalance(t->leftChild) >= 0)
return rotateWithRightChild(t);
if (balance > 1 && getBalance(t->leftChild) < 0)
{
t->leftChild = rotateWithLeftChild(t->leftChild);
return rotateWithRightChild(t);
}
if (balance < -1 && getBalance(t->rightChild) <= 0)
return rotateWithLeftChild(t);
if (balance < -1 && getBalance(t->rightChild) > 0)
{
t->rightChild = rotateWithRightChild(t->rightChild);
return rotateWithLeftChild(t);
}
return t;
}
I'm assuming your code for updating heights and balancing the rooted sub-tree is correct since I've forgotten about it's theory and will need to revise.
I am coding a binary search tree.
class Node {
public:
Node* left;
Node* right;
int data;
Node(int x) : data(x) {}
void insert(int value) {
if (value < data) {
if (left == NULL)
left = new Node(value);
else
left->insert(value);
} else {
if (right == NULL)
right = new Node(value);
else
right->insert(value);
}
}
bool contains(int value) {
if (value == data)
return true;
else if (value < data) {
if (left == NULL)
return false;
else
return left->contains(value);
} else {
if (right == NULL)
return false;
else
return right->contains(value);
}
}
};
When I use Node x in the main program and then call x.insert(15) it gives a segmentation error. If I use Node* x=new Node(10) and then use x->insert(15) instead then it works fine. What is the reasoning behind that?
int main() {
Node x(10);
x.insert(15);
}
The main problem is that you don't initialize the pointers (left and right) with nullptr but you assume they are initialized with a null pointer in insert. Doing the initialization in the constructor fixes the issue:
Node(int x) : data{x}, left{nullptr}, right{nullptr} {}
I am using Visiual Studio 2013. For some reason, I am getting the following error:
Error 1 error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Word &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#AAVWord###Z) referenced in function "protected: virtual void __thiscall BST<class Word>::visit(class BSTNode<class Word> *)" (?visit#?$BST#VWord####MAEXPAV?$BSTNode#VWord#####Z) C:\Users\Reuben\documents\visual studio 2013\Projects\CS321 Lab4\CS321 Lab4\main.obj CS321 Lab4
The error is due to this particular line:
BST<Word> tree;
If the line were as follows, then it seems to compile just fine:
BST<int> tree;OR BST<string> tree;
So for some reason, it's not liking my implementation of the Word class I defined. Here is the following code.
main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Word.h"
#include "genBST.h"
using namespace std;
int main()
{
BST<Word> tree;
system("pause");
return 0;
}
Word.h
#include <string>
#include <set>
using namespace std;
class Word{
public:
string* word;
set<int>* lineNums;
void addLineNum(int);
Word(string*, int);
Word();
friend ostream& operator<<(ostream& out, Word& pr);
friend bool operator==(Word, Word);
friend bool operator!=(Word, Word);
friend bool operator<(Word, Word);
friend bool operator<=(Word, Word);
friend bool operator>=(Word, Word);
friend bool operator>(Word, Word);
};
Word::Word(string* myWord, int myLineNum) {
word = myWord;
set<int>* lineNums = new set<int>();
lineNums->insert(myLineNum);
}
Word::Word()
{
word = new string("");
set<int>* lineNums = new set<int>();
lineNums->insert(1);
}
void Word::addLineNum(int line)
{
lineNums->insert(line);
}
//overload comparison operators
//take note that the order of these are important
//since some of the operators are defined in terms of the previously defined ones
bool operator==(Word word1, Word word2)
{
if (*(word1.word) == *(word2.word))
{
return true;
}
return false;
}
bool operator!=(Word word1, Word word2)
{
return !(word1 == word2);
}
bool operator<=(Word word1, Word word2)
{
if (*(word1.word) <= *(word2.word))
{
return true;
}
return false;
}
bool operator<(Word word1, Word word2)
{
if (word1 <= word2 && word1 != word2)
return true;
return false;
}
bool operator>(Word word1, Word word2)
{
return !(word1 <= word2);
}
bool operator>=(Word word1, Word word2)
{
return !(word1 < word2);
}
std::ostream& operator<<(std::ostream& out, const Word& word1)
{
out << *(word1.word);
out << ": ";
set<int>::iterator it;
for (it = word1.lineNums->begin(); it != word1.lineNums->end(); it++)
{
out << *it << " ";
}
return out;
}
The last file is genBST.h. It's a long file, so I'm posting it last. This file was given to me as part of my assignment and we are not allowed to make changes to this file or else we will lose points.
//************************ genBST.h **************************
// generic binary search tree
#include <queue>
#include <stack>
#ifndef BINARY_SEARCH_TREE
#define BINARY_SEARCH_TREE
template<class T>
class Stack : public stack<T> {
public:
T pop() {
T tmp = top();
stack<T>::pop();
return tmp;
}
};
template<class T>
class Queue : public queue<T> {
public:
T dequeue() {
T tmp = front();
queue<T>::pop();
return tmp;
}
void enqueue(const T& el) {
push(el);
}
};
template<class T> class BST;
template<class T>
class BSTNode {
public:
BSTNode() {
left = right = 0;
}
BSTNode(const T& e, BSTNode<T> *l = 0, BSTNode<T> *r = 0) {
el = e; left = l; right = r;
}
T el;
BSTNode<T> *left, *right;
};
template<class T>
class BST {
public:
BST() {
root = 0;
}
~BST() {
clear();
}
void clear() {
clear(root);
root = 0;
}
bool isEmpty() const {
return root == 0;
}
void preorder() {
preorder(root);
}
void inorder() {
inorder(root);
}
void postorder() {
postorder(root);
}
void insert(const T&);
void recursiveInsert(const T& el) {
recursiveInsert(root, el);
}
T* search(const T& el) const {
return search(root, el);
}
T* recursiveSearch(const T& el) const {
return recursiveSearch(root, el);
}
void deleteByCopying(BSTNode<T>*&);
void findAndDeleteByCopying(const T&);
void deleteByMerging(BSTNode<T>*&);
void findAndDeleteByMerging(const T&);
void iterativePreorder();
void iterativeInorder();
void iterativePostorder();
void breadthFirst();
void MorrisPreorder();
void MorrisInorder();
void MorrisPostorder();
void balance(T*, int, int);
protected:
BSTNode<T>* root;
void clear(BSTNode<T>*);
void recursiveInsert(BSTNode<T>*&, const T&);
T* search(BSTNode<T>*, const T&) const;
T* recursiveSearch(BSTNode<T>*, const T&) const;
void preorder(BSTNode<T>*);
void inorder(BSTNode<T>*);
void postorder(BSTNode<T>*);
virtual void visit(BSTNode<T>* p)
{
cout << p->el << ' ';
}
};
template<class T>
void BST<T>::clear(BSTNode<T> *p) {
if (p != 0) {
clear(p->left);
clear(p->right);
delete p;
}
}
template<class T>
void BST<T>::insert(const T& el) {
BSTNode<T> *p = root, *prev = 0;
while (p != 0) { // find a place for inserting new node;
prev = p;
if (el < p->el)
p = p->left;
else p = p->right;
}
if (root == 0) // tree is empty;
root = new BSTNode<T>(el);
else if (el < prev->el)
prev->left = new BSTNode<T>(el);
else prev->right = new BSTNode<T>(el);
}
template<class T>
void BST<T>::recursiveInsert(BSTNode<T>*& p, const T& el) {
if (p == 0)
p = new BSTNode<T>(el);
else if (el < p->el)
recursiveInsert(p->left, el);
else recursiveInsert(p->right, el);
}
template<class T>
T* BST<T>::search(BSTNode<T>* p, const T& el) const {
while (p != 0)
if (el == p->el)
return &p->el;
else if (el < p->el)
p = p->left;
else p = p->right;
return 0;
}
template<class T>
T* BST<T>::recursiveSearch(BSTNode<T>* p, const T& el) const {
if (p != 0)
if (el == p->el)
return &p->el;
else if (el < p->el)
return recursiveSearch(p->left, el);
else return recursiveSearch(p->right, el);
else return 0;
}
template<class T>
void BST<T>::inorder(BSTNode<T> *p) {
if (p != 0) {
inorder(p->left);
visit(p);
inorder(p->right);
}
}
template<class T>
void BST<T>::preorder(BSTNode<T> *p) {
if (p != 0) {
visit(p);
preorder(p->left);
preorder(p->right);
}
}
template<class T>
void BST<T>::postorder(BSTNode<T>* p) {
if (p != 0) {
postorder(p->left);
postorder(p->right);
visit(p);
}
}
template<class T>
void BST<T>::deleteByCopying(BSTNode<T>*& node) {
BSTNode<T> *previous, *tmp = node;
if (node->right == 0) // node has no right child;
node = node->left;
else if (node->left == 0) // node has no left child;
node = node->right;
else {
tmp = node->left // node has both children;
previous = node; // 1.
while (tmp->right != 0) { // 2.
previous = tmp;
tmp = tmp->right;
}
node->el = tmp->el; // 3.
if (previous == node)
previous->left = tmp->left;
else previous->right = tmp->left; // 4.
}
delete tmp; // 5.
}
// findAndDeleteByCopying() searches the tree to locate the node containing
// el. If the node is located, the function DeleteByCopying() is called.
template<class T>
void BST<T>::findAndDeleteByCopying(const T& el) {
BSTNode<T> *p = root, *prev = 0;
while (p != 0 && !(p->el == el)) {
prev = p;
if (el < p->el)
p = p->left;
else p = p->right;
}
if (p != 0 && p->el == el)
if (p == root)
deleteByCopying(root);
else if (prev->left == p)
deleteByCopying(prev->left);
else deleteByCopying(prev->right);
else if (root != 0)
cout << "el " << el << " is not in the tree\n";
else cout << "the tree is empty\n";
}
template<class T>
void BST<T>::deleteByMerging(BSTNode<T>*& node) {
BSTNode<T> *tmp = node;
if (node != 0) {
if (!node->right) // node has no right child: its left
node = node->left; // child (if any) is attached to its parent;
else if (node->left == 0) // node has no left child: its right
node = node->right; // child is attached to its parent;
else { // be ready for merging subtrees;
tmp = node->left; // 1. move left
while (tmp->right != 0)// 2. and then right as far as possible;
tmp = tmp->right;
tmp->right = // 3. establish the link between the
node->right; // the rightmost node of the left
// subtree and the right subtree;
tmp = node; // 4.
node = node->left; // 5.
}
delete tmp; // 6.
}
}
template<class T>
void BST<T>::findAndDeleteByMerging(const T& el) {
BSTNode<T> *node = root, *prev = 0;
while (node != 0) {
if (node->el == el)
break;
prev = node;
if (el < node->el)
node = node->left;
else node = node->right;
}
if (node != 0 && node->el == el)
if (node == root)
deleteByMerging(root);
else if (prev->left == node)
deleteByMerging(prev->left);
else deleteByMerging(prev->right);
else if (root != 0)
cout << "el " << el << " is not in the tree\n";
else cout << "the tree is empty\n";
}
template<class T>
void BST<T>::iterativePreorder() {
Stack<BSTNode<T>*> travStack;
BSTNode<T> *p = root;
if (p != 0) {
travStack.push(p);
while (!travStack.empty()) {
p = travStack.pop();
visit(p);
if (p->right != 0)
travStack.push(p->right);
if (p->left != 0) // left child pushed after right
travStack.push(p->left); // to be on the top of the stack;
}
}
}
template<class T>
void BST<T>::iterativeInorder() {
Stack<BSTNode<T>*> travStack;
BSTNode<T> *p = root;
while (p != 0) {
while (p != 0) { // stack the right child (if any)
if (p->right) // and the node itself when going
travStack.push(p->right); // to the left;
travStack.push(p);
p = p->left;
}
p = travStack.pop(); // pop a node with no left child
while (!travStack.empty() && p->right == 0) { // visit it and all nodes
visit(p); // with no right child;
p = travStack.pop();
}
visit(p); // visit also the first node with
if (!travStack.empty()) // a right child (if any);
p = travStack.pop();
else p = 0;
}
}
template<class T>
void BST<T>::iterativePostorder() {
Stack<BSTNode<T>*> travStack;
BSTNode<T>* p = root, *q = root;
while (p != 0) {
for (; p->left != 0; p = p->left)
travStack.push(p);
while (p->right == 0 || p->right == q) {
visit(p);
q = p;
if (travStack.empty())
return;
p = travStack.pop();
}
travStack.push(p);
p = p->right;
}
}
template<class T>
void BST<T>::breadthFirst() {
Queue<BSTNode<T>*> queue;
BSTNode<T> *p = root;
if (p != 0) {
queue.enqueue(p);
while (!queue.empty()) {
p = queue.dequeue();
visit(p);
if (p->left != 0)
queue.enqueue(p->left);
if (p->right != 0)
queue.enqueue(p->right);
}
}
}
template<class T>
void BST<T>::MorrisInorder() {
BSTNode<T> *p = root, *tmp;
while (p != 0)
if (p->left == 0) {
visit(p);
p = p->right;
}
else {
tmp = p->left;
while (tmp->right != 0 &&// go to the rightmost node of
tmp->right != p) // the left subtree or
tmp = tmp->right; // to the temporary parent of p;
if (tmp->right == 0) { // if 'true' rightmost node was
tmp->right = p; // reached, make it a temporary
p = p->left; // parent of the current root,
}
else { // else a temporary parent has been
visit(p); // found; visit node p and then cut
tmp->right = 0; // the right pointer of the current
p = p->right; // parent, whereby it ceases to be
} // a parent;
}
}
template<class T>
void BST<T>::MorrisPreorder() {
BSTNode<T> *p = root, *tmp;
while (p != 0) {
if (p->left == 0) {
visit(p);
p = p->right;
}
else {
tmp = p->left;
while (tmp->right != 0 &&// go to the rightmost node of
tmp->right != p) // the left subtree or
tmp = tmp->right; // to the temporary parent of p;
if (tmp->right == 0) { // if 'true' rightmost node was
visit(p); // reached, visit the root and
tmp->right = p; // make the rightmost node a temporary
p = p->left; // parent of the current root,
}
else { // else a temporary parent has been
tmp->right = 0; // found; cut the right pointer of
p = p->right; // the current parent, whereby it ceases
} // to be a parent;
}
}
}
template<class T>
void BST<T>::MorrisPostorder() {
BSTNode<T> *p = new BSTNode<T>(), *tmp, *q, *r, *s;
p->left = root;
while (p != 0)
if (p->left == 0)
p = p->right;
else {
tmp = p->left;
while (tmp->right != 0 &&// go to the rightmost node of
tmp->right != p) // the left subtree or
tmp = tmp->right; // to the temporary parent of p;
if (tmp->right == 0) { // if 'true' rightmost node was
tmp->right = p; // reached, make it a temporary
p = p->left; // parent of the current root,
}
else { // else a temporary parent has been found;
// process nodes between p->left (included) and p (excluded)
// extended to the right in modified tree in reverse order;
// the first loop descends this chain of nodes and reverses
// right pointers; the second loop goes back, visits nodes,
// and reverses right pointers again to restore the pointers
// to their original setting;
for (q = p->left, r = q->right, s = r->right;
r != p; q = r, r = s, s = s->right)
r->right = q;
for (s = q->right; q != p->left;
q->right = r, r = q, q = s, s = s->right)
visit(q);
visit(p->left); // visit node p->left and then cut
tmp->right = 0; // the right pointer of the current
p = p->right; // parent, whereby it ceases to be
} // a parent;
}
}
template<class T>
void BST<T>::balance(T data[], int first, int last) {
if (first <= last) {
int middle = (first + last) / 2;
insert(data[middle]);
balance(data, first, middle - 1);
balance(data, middle + 1, last);
}
}
#endif
Any help would be appreciated! I'm still learning the basics of c++, I transferred schools so I'm trying to learn c++ (as opposed to Java which is what I was doing before at my other school). Thanks in advance!
EDIT: Oops, I was being dumb, the following line of code:
friend ostream& operator<<(ostream& out, Word& pr);
Should be (I think):
friend ostream& operator<<(ostream, const Word);
However, after this change, I still get the following error:
Error 1 error C2593: 'operator <<' is ambiguous c:\users\reuben\documents\visual studio 2013\projects\cs321 lab4\cs321 lab4\genbst.h 105 1 CS321 Lab4
Where the line 105 refers is the statement in the function (in the genBST.h file):
virtual void visit(BSTNode<T>* p)
{
cout << p->el << ' ';
}
EDIT v2:
Ok, I've changed the code and it seems to work now. I just placed the implementation of the << operator inside the declaration like so:
class Word{
public:
string* word;
set<int>* lineNums;
void addLineNum(int);
Word(string*, int);
Word();
friend ostream& operator<<(ostream& out, const Word& word1 )
{
out << *(word1.word);
out << ": ";
set<int>::iterator it;
for (it = word1.lineNums->begin(); it != word1.lineNums->end(); it++)
{
out << *it << " ";
}
return out;
};
friend bool operator==(Word, Word);
friend bool operator!=(Word, Word);
friend bool operator<(Word, Word);
friend bool operator<=(Word, Word);
friend bool operator>=(Word, Word);
friend bool operator>(Word, Word);
};
And it seems to work now.
I noticed that in your class definition you have:
class Word{
public:
string* word;
set<int>* lineNums;
void addLineNum(int);
Word(string*, int);
Word();
friend ostream& operator<<(ostream& out, Word& pr);
there is no const before Word & pr
however later in your code you have:
std::ostream& operator<<(std::ostream& out, const Word& word1)
see , there is a const here before Word& word1
should make them same( both have const), I think
I tried your code on my Visual Stdio 2010 ( I do not have 2013).
Before I adding the keyword const (before Word & pr) I got same error as you.
However, after I added the const, it was built successfully.
What is the error you got after you add the keyword const ? Post in detail here.
Just showing how the node of the binary tree looks like. I'm not sure what is wrong but I have a feeling it has something to do with the function being private. How I can compare the private data so I can see if the value I am looking for is inside that node?
class binarytree
{
private:
class node
{
public:
int data;
node * left;
node * right;
node (int x)
{
data = x;
left=NULL;
right=NULL;
}
};
node * root;
This is how I insert the node
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
//insert left
insert(x, r->left);
}
else
{
//insert right
insert(x, r->right);
}
}
}
Here is the part of the code that gives me trouble when I try to compare x to r->data the program crashes and gives me the error message " Access violation reading location 0x00000000"
void remove(int x, node * &r)
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
This is where the functions are publicly. Then I call the private functions so I can manipulate the private tree.
public:
binarytree()
{
root = NULL;
}
~binarytree()
{
//tooo: write this
}
//return true if empty, false if not
bool empty()
{}
void insert(int x)
{
insert(x, root);
}
void remove(int x)
{
remove(x,root);
}
};
EDIT: Here is another function of the program that works but might be causing r to point to NULL.
int extractMin(node * &r)
{
if(r->left == NULL)
{
if(r->right == NULL)
{
return r->data;
}
else
{
int x = r->data;
r = r->right;
return x;
}
}
else
{
return extractMin(r->left);
}
}
Here is the new function to check to see if r is NULL
void remove(int x, node * &r)
{
if(r == NULL)
{
cout<<"why am I null?"<<endl;
}
else
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
}
you should always check for NULL before trying to get to the inner members:
void remove(int x, node * &r)
{
if(r != NULL)
{
// Your code
}
}
you call to remove with r as NULL and then try to check r.Left. then here you have access violation
also i must ask, did any if this worked for you? specifically insert wont work this way.
try
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
if(r->left != NULL)
{
//insert left
insert(x, r->left);
}
else
{
r->left = new node(x);
}
}
else
{
if(r->right != NULL)
{
//insert right
insert(x, r->right);
}
else
{
r->left = new node(x);
}
}
}
}
r is null somehow. You need to check if the r passed in is NULL, or check if the root is non-null, and call remove on children only if they exist.
Well it the error says, r is pointing to NULL when you try to derefference it.
So you have to make sure when you assign memmory to r it doesn't return NULL.
binarytree()
{
root = NULL;
}
void remove(int x)
{
remove(x,root);
}
In your case you are trying to derefference NULL (as the error says) This happens in your code when you are calling a remove before you have called an insert.
You simply should check at the beginning of remove for r isn't pointing to NULL.
Or even better, make sure you won't parse in r when its NULL.
You are comparing x to the root. When your tree is empty, root == nullptr. You should check to see if r == nullptr first, as in:
bool remove(int x, node * &r) {
if(!r) {
return false; // Indicate whether removal succeeded
}
//... etc.
}
I am getting a few errors in my Binary Search Tree print code and I do not know why. (Errors at the bottom)
#ifndef MYBSTREE_H
#define MYBSTREE_H
#include "abstractbstree.h"
#include "abstractstack.h"
using namespace std;
class LinkedStack *head = NULL; //LINE 7
template<typename T>
class TreeNode
{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
};
template<typename T>
class LinkedStack: public AbstractStack<TreeNode<T>*>
{
public:
TreeNode<T>* m_data;
LinkedStack *m_next;
LinkedStack()
{
if(head != NULL)
head = new LinkedStack;
m_data = 0;
m_next = NULL;
}
void clear()
{
while(head -> m_next != NULL)
{
LinkedStack *tmp = head -> m_next;
head -> m_ldata= tmp -> m_ldata;
head -> m_next = tmp -> m_next;
delete tmp;
}
}
void push(TreeNode<T>* x)
{
LinkedStack *tmp = new LinkedStack;
tmp -> m_data = m_data;
tmp -> m_next = m_next;
m_data = x;
m_next = tmp;
}
void pop()
{
if (isEmpty())
cout<<"Panic! Nothing to pop"<<endl;
else
{
LinkedStack *tmp;
tmp = m_next;
m_data = tmp -> m_data;
m_next = tmp -> m_next;
delete tmp;
}
}
int& top()
{
if (isEmpty())
cout<<"Panic! List is Empty"<<endl;
return m_ldata;
}
bool isEmpty()
{
bool empty = false;
if (m_next == NULL)
{
empty = true;
}
return empty;
}
};
template<typename T>
class MyBSTree:public AbstractBSTree<T>
{
private:
TreeNode<T>* m_root;
public:
~MyBSTree()
{
clear();
}
MyBSTree()
{
m_root -> m_data = T();
m_root -> m_right = NULL;
m_root -> m_left = NULL;
};
int size() const
{
if(m_root==NULL)
return 0;
else
return (size(m_root->m_left)+1+size(m_root->m_right));
}
bool isEmpty() const
{
if (m_root== NULL)
return true;
else
return false;
}
int height() const
{
int lh,rh;
if(m_root==NULL)
{
return 0;
}
else
{
lh = height(m_root->m_left);
rh = height(m_root->m_right);
if(lh > rh)
return lh + 1;
else
return rh + 1;
}
}
const T& findMax() const
{
TreeNode<T>* p = m_root;
while(p -> m_right != NULL)
p = p -> m_right;
return p;
}
const T& findMin() const
{
TreeNode<T>* p = m_root;
while(p -> m_left != NULL)
p = p -> m_left;
return p;
}
/*
int contains(const T& x) const;
*/
void clear()
{
delete m_root;
}
void insert(const T& x)
{
TreeNode<T>* p = m_root;
do
{
if (x == p -> m_root)
return;
else if ( x < p->m_data)
{
if(p->m_left == NULL)
{
p->m_left = new TreeNode<T>;
p -> m_left -> m_data = x;
return;
}
else
p = p -> m_left;
}
else if( x > p->m_data)
{
if(p->m_right == NULL)
{
p->m_right = new TreeNode<T>;
p-> m_right -> m_data = x;
return;
}
else
p = p -> m_right;
}
}while(p -> m_right != NULL && p -> m_left != NULL);
}
void remove(const T& x)
{
if(m_root == NULL)
return;
TreeNode<T>* q = m_root;
TreeNode<T>* p;
while(q != NULL)
{
if(m_root->m_data == x)
{
delete q;
return;
}
else if(x > q->m_data)
{
p = q;
q = q->m_right;
}
else
{
p = q;
q = q->m_left;
}
}
if(q->m_left == NULL && q->m_right == NULL)
{
if(p == q)
delete p;
else if(p->m_left == q)
{
p->m_left = NULL;
delete q;
}
else
{
p->m_right = NULL;
delete q;
}
return;
}
if((q->m_left == NULL && q->m_right != NULL) || (q->m_left != NULL && q->m_right == NULL))
{
if(q->m_left == NULL && q->m_right != NULL)
{
if(p->m_left == q)
{
p->m_left = q->m_right;
delete q;
}
else
{
p->m_right = q->m_right;
delete q;
}
}
else
{
if(p->m_left == q)
{
p->m_left = q->m_left;
delete q;
}
else
{
p->m_right = q->m_left;
delete q;
}
}
return;
}
if (q->m_left != NULL && q->m_right != NULL)
{
TreeNode<T>* check;
check = q->m_right;
if((check->m_left == NULL) && (check->m_right == NULL))
{
q = check;
delete check;
q->m_right = NULL;
}
else
{
if((q->m_right)->m_left != NULL)
{
TreeNode<T>* m_leftq;
TreeNode<T>* m_leftp;
m_leftp = q->m_right;
m_leftq = (q->m_right)->m_left;
while(m_leftq->m_left != NULL)
{
m_leftp = m_leftq;
m_leftq = m_leftq->m_left;
}
q->data = m_leftq->data;
delete m_leftq;
m_leftp->m_left = NULL;
}
else
{
TreeNode<T>* tmp;
tmp = q->m_right;
q->data = tmp->data;
q->m_right = tmp->m_right;
delete tmp;
}
}
return;
}
}
void printPreOrder() const
{
LinkedStack stack;
stack<T>.push(m_root); //THIS LINE
while(!stack.isEmpty()) //THIS LINE
{
TreeNode<T>* root = stack.push(); //THIS LINE
stack.pop(); //THIS LINE
if(root!= NULL)
{
stack.push(root->right); //THIS LINE
stack.push(root->m_left); //THIS LINE
cout << root->m_data << " ";
}
}
}
/*
void printPostOrder() const;
void print() const;
*/
};
#endif
What I am getting are errors that say:
MyBSTree.h: In member function âvoid MyBSTree<T>::printPreOrder() constâ:
MyBSTree.h:362:9: error: invalid use of incomplete type âstruct LinkedStackâ
MyBSTree.h:7:7: error: forward declaration of âstruct LinkedStackâ
I get that for all the lines I have marked in that particular function. I'm pretty sure it has something to do with template syntax, but I'm not sure.
Line class LinkedStack *head = NULL; has no sense. If you want to have a head to your LinkedStack, you should:
drop the class in this line
pass correct type since it's a template
do it after the templated class definition
Something like this: LinkedStack<your type> *head = NULL;
I don't understande what you mean by
class LinkedStack *head = NULL; //LINE 7
Is this supposed to be the forward declaration? in this case it should be
template<typename T>
class LinkedStack;
If after that you are trying to initialize an instance, then it should be
LinkedStack<int> *head = NULL; //int as a typename T
but you can't mix both in one line :)