Binary tree search doesn't work - c++

template<class T>
class Tree {
public:
Tree(TreeNode *rootPtr = NULL)
{
this->rootPtr = rootPtr;
};
TreeNode<T> *search(string x);
bool insert(T x);
TreeNode * remove(T x);
TreeNode *getRoot(){ return rootPtr; };
Tree getLeftSubtree(); Tree getRightSubtree();
bool isEmpty(){ return rootPtr == NULL; };
private:
TreeNode<T> *rootPtr;
};
I get this error
C2955: 'TreeNode' : use of class template requires template argument list
The TreeNode class is:
template <class T>
class TreeNode{
T data; // different data type for other apps
TreeNode<T> *left; // a pointer to left child
TreeNode<T> *right; // a pointer to right child
public:
TreeNode(T x = 0, TreeNode *left = NULL,TreeNode *right = NULL)
{
data = x;
this->left = left;
this->right = right;
};
T getData() { return data; };
TreeNode<T> *getLeft() { return left; };
TreeNode<T> *getRight() { return right; };
void setData(T x) { data = x; };
void setLeft(TreeNode *ptr) { left = ptr; };
void setRight(TreeNode *ptr) { right = ptr; };
template<class T> friend class Tree;
};

I appended the code for the TreeNode class posted here into the question - TonyD

Related

Cannot implement array initialization in TreeNode Template C++ Scapegoat Tree

I get an initialization error for a TreeNode class constructor… This is the function:
TreeNode* a = new TreeNodens; Is the issue here, not sure what I have to add to TreeNode but it needs some type of tweak!
template <typename T>
void ScapegoatST<T>::rebuild(TreeNode<T>* node){
int ns = getHeight(node);
TreeNode<T>* p = node->getParent();
TreeNode<T>* a = new TreeNode<T>[ns]();
TreeNode<T>* r;
packintoArray(node,a,0);
if (p == NULL){
r = buildBalanced(a,0,ns);
r->setParent(NULL);
} else if (p->getRight() == node){
TreeNode<T>* Tr = buildBalanced(a, 0, ns);
p->setRight(Tr);
p->getRight()->setParent(p);
} else {
p->setLeft(buildBalanced(a,0,ns));
p->getLeft()->setParent(p);
}
}
Here is the TreeNode.h:
#ifndef TREE_NODE_H
#define TREE_NODE_H
#include <cstdlib>
#include <iostream>
using namespace std;
template <typename T>
class TreeNode{
public:
TreeNode(T nData);
virtual ~TreeNode();
T getData();
TreeNode<T>* getLeft();
TreeNode<T>* getRight();
TreeNode<T>* getParent();
void setData(T nData);
void setLeft(TreeNode<T>* nleft){left=nleft;};
void setRight(TreeNode<T>* nright){right=nright;};
void setParent(TreeNode<T>* nparent){parent=nparent;};
template <typename S>
friend class ScapegoatST;
private:
T data;
TreeNode<T>* left;
TreeNode<T>* right;
TreeNode<T>* parent;
};
template <typename T>
TreeNode<T>::TreeNode(T nData){
data = nData;
left = NULL;
right = NULL;
}
template <typename T>
TreeNode<T>::~TreeNode(){
delete left;
delete right;
delete parent;
data = NULL;
}
template <typename T>
T TreeNode<T>::getData(){
return data;
}
template <typename T>
void TreeNode<T>::setData(T nData){
data = nData;
}
#endif
I tired creating a constructor for the array initialization but it wasn’t successful.
The issue here is that you've created the constructor TreeNode(T nData), which prevents the constructor with no arguments TreeNode() from being generated, but you call that constructor when you do new TreeNode<T>[ns]().
One solution would be to add a constructor TreeNode(), with a body like so:
template<typename T>
TreeNode<T>::TreeNode() {
left = NULL;
right = NULL;
}
This will mean that constructing a TreeNode with no nData will result in the node's data field being default-initialized (for primitive types, it will contain an undefined value, and for classes it will act like T() was called to construct the data value).

Why do I get compile errors when I try to make this constructor generic?

So I have these three classes made
template <class dataType>
class listEntry
{
private:
dataType data;
public:
listEntry *next;
listEntry *prev;
dataType getData() { return this->data; }
listEntry();
listEntry(dataType data) { this->data = data; }
~listEntry() {};
};
template <class dataType>
class List
{
private:
dataType *head;
dataType *tail;
int count;
public:
dataType *getHead() { return this->head; }
dataType *getTail() { return this->tail; }
void addToTail(dataType *newEntry);
void addToHead(dataType *newEntry);
int getCount() { return count; }
void printListForward();
List();
List(const List<dataType> &li);
~List();
};
template <class dataType>
class Queue: public List<dataType>
{
public:
void enQueue(dataType *newEntry);
Queue():List<dataType>() { return; }
Queue(const List<dataType>& li):List<dataType>(li) { return; }
Queue(dataType data);
Queue(listEntry<dataType> le);
}
And one of my constructors for the Queue is this:
template <class dataType>
Queue<dataType>::Queue(dataType data)
{
enQueue(new listEntry<int>(data));
}
However, I want enQueue(new listEntry<int>(data)); to be enQueue(new listEntry<dataType>(data)); so that it is generic and can work with any data type. But when I change it to that, I get compile errors.
The enQueue definition looks like this:
template <class dataType>
void Queue<dataType>::enQueue(dataType *newEntry)
{
this->addToTail(newEntry);
}
How come writing dataType instead of int gets compile errors?
There are some design issues with your code:
The head and tail members of List need to be declared as listEntry<dataType>* instead of as dataType*.
addToTail(), addToHead() and enQueue() should all take dataType values instead of dataType* pointers.
addToTail() and addToHead() need to create a new listEntry<dataType> object internally.
Try something more like this instead:
template <class dataType>
class listEntry
{
private:
dataType data;
public:
listEntry *prev;
listEntry *next;
dataType getData() const { return data; }
listEntry(const dataType &data, listEntry *prev = NULL, listEntry *next = NULL);
};
template <class dataType>
class List
{
public:
typedef listEntry<dataType> entryType;
private:
entryType *head;
entryType *tail;
int count;
public:
entryType* getHead() { return head; }
const entryType* getHead() const { return head; }
entryType* getTail() { return tail; }
const entryType* getTail() const { return tail; }
void addToTail(const dataType &data);
void addToHead(const dataType &data);
int getCount() const { return count; }
void printListForward() const;
List();
List(const List &li);
~List();
List& operator=(const List &li);
};
template <class dataType>
class Queue : public List<dataType>
{
public:
typedef List<dataType> listType;
void enQueue(const dataType &data);
Queue() {}
Queue(const Queue &q) : listType(q) {}
Queue(const listType &li) : listType(li) {}
Queue(const dataType &data);
};
...
template<class dataType>
listEntry<dataType>::listEntry(const dataType &data, listEntry *prev, listEntry *next)
: data(data), prev(prev), next(next)
{
}
template<class dataType>
void List<dataType>::addToTail(const dataType &data)
{
entryType *newEntry = new entryType(data, tail);
if (!head) head = newEntry;
if (tail) tail->next = newEntry;
tail = newEntry;
++count;
}
template<class dataType>
void List<dataType>::addToHead(const dataType &data)
{
entryType *newEntry = new entryType(data, NULL, head);
if (!tail) tail = newEntry;
if (head) head->prev = newEntry;
head = newEntry;
++count;
}
template<class dataType>
void List<dataType>::printListForward() const
{
entryType *entry = head;
while (entry)
{
//...
entry = entry->next;
}
}
template<class dataType>
void List<dataType>::List()
: head(NULL), tail(NULL), count(0)
{
}
template<class dataType>
void List<dataType>::List(const List<dataType> &li)
: head(NULL), tail(NULL), count(0)
{
const entryType *entry = li.getHead();
while (entry)
{
addToTail(entry->getData());
entry = entry->next;
}
}
template<class dataType>
void List<dataType>::~List()
{
entryType *entry = head;
while (entry)
{
entryType *next = entry->next;
delete entry;
entry = next;
}
}
template<class dataType>
List<dataType>& List<dataType>::operator=(const List<dataType> &li)
{
if (&li != this)
{
List<dataType> temp(li);
std::swap(head, temp.head);
std::swap(tail, temp.tail);
std::swap(count, temp.count);
}
return *this;
}
template <class dataType>
Queue<dataType>::Queue(const dataType &data)
{
enQueue(data);
}
template <class dataType>
void Queue<dataType>::enQueue(const dataType &data)
{
addToTail(data);
}
Then you can do things like this:
Queue<int> q;
q.enQueue(12345);
q.enQueue(67890);
q.printListForward();

Segmentation fault (C++ pointers)

I'm trying to implement a linked list class in C++ using a node class and a pointer to the next node.
template<class T>
class Node {
public: T val;
public: Node* next;
public: Node() { }
public: Node(T val) { this.val = val; }
};
I created a linked list class with a pointer to the head and a function append to add nodes to the list:
template<class T>
class LinkedList {
private: Node<T>* head;
public: LinkedList() { }
public: LinkedList(T val) { head -> val = val; }
public: void append(T val) {
Node<T>* temp = head;
while(temp -> val != NULL) {
temp = temp -> next;
}
temp -> val = val;
}
};
but after compilation and running, it throws this error "Segmentation fault (core dumped)"
I know a little about segmentation fault like trying to access a memory location that is no longer existed but I don't get it in this example, any help??
The main problem is that you don't initialize the next pointer with null pointer, but you assume it is null pointer by default. Here's how you fix it:
template <class T>
class Node {
public:
T val;
Node* next;
Node( T val_ = {} )
: val{ val_ }
, next{ nullptr }
{ }
};
Besides that, in the append there are problems. Here's how the code should have looked like completely:
template <class T>
class Node {
public:
T val;
Node* next;
Node(T val_ = {}) : val{ val_ }, next{ nullptr } {}
};
template <class T>
class LinkedList {
private:
Node<T>* head;
public:
LinkedList(T val_ = {}) : head{ new Node{val_} } {}
void append(T val) {
Node<T>* temp = head;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new Node<T>{ val };
}
};
int main() {
LinkedList<int> l;
l.append(10);
}
Other comments:
this.val won't compile, because this is a pointer. You meant this->val.
You should consider using member initializer lists instead of this->val = val.
Initialize all members in all constructors.

No default constructor for class member that is a template object itself

I'm trying to write a simple class for binary search tree that uses a class of nodes using templates. This is my code:
When I try to compile the code I get this error:
'Node<T>': no appropriate default constructor available'
for this line:
Tree() : root(0), counter(0) {}
and I don't understand why it would even use a default constructor here I'm just giving a value to a pointer of the class type.
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Node {
public:
Node(const T &value) : value(value), Left(0), Right(0) {}
~Node() {
if (Left != 0)
delete Left;
if (Right != 0)
delete Right;
}
Node& getLeft() { return *Left; }
Node& getRight() { return *Right; }
private:
Node* Left;
Node* Right;
T value;
};
template <typename T>
class Tree : public Node<T> {
public:
template<typename T>
friend ostream& operator<<(ostream& output, const Tree<T> &t);
Tree() : root(0), counter(0) {}
Tree(const T &rootValue) : root(new Node<T>(rootValue)), counter(1) {}
~Tree() { delete root; }
Tree& insert(const T &value) {
Node<T> *runner = root;
Node<T> *replacer = root;
if (runner == 0)
root = new Node<T>(value);
else
{
while (runner != 0)
{
replacer = runner;
if (value > runner->value)
runner = runner->Right;
else
runner = runner->Left;
}
if (value > replacer->value)
replacer->Right = new Node<T>(value);
else
replacer->Left = new Node<T>(value);
}
counter++;
return *this;
}
bool exists(const T &value) const {
Node<T> *runner = root;
while (runner != 0)
{
if (value == runner->value)
return true;
if (value > runner->value)
runner = runner->Right;
else
runner = runner->Left;
}
return false;
}
int size() const { return size; }
private:
Node<T> *root;
int counter;
};
template<typename T>
string preorderToString(const Node<T> &n) { //Function that receives a tree and returns a string of the preorder traversal of it
string left, middle, right;
if (n.Left != 0)
left = preorderToString((*n.Left)) + " ";
middle = to_string(n.value);
if (n.Right != 0)
right = " " + preorderToString((*n.Right));
return left + middle + right;
}
template<typename T>
ostream& operator<<(ostream& output, const Tree<T> &t) //Operator overloading that uses the function 'preorderToString' to print the tree contents
{
return output << preorderToString<T>(*(t.root));
}
int main() {
Tree<double> test;
}
The message is a little misleading: it's not complaining about the members you've initialised, but the base that you didn't initialise. Therefore it's trying to use a default constructor of the base (Node<double>) that doesn't exist.
Perhaps you didn't mean to make Tree<T> derive from Node<T>?
Fixing that (and the shadowed T on that friend declaration), the code compiles.

Generic binary tree node destructor issue

I've been working on an assignment and now I'm stuck with buggy destructors. I have to create a generic binary tree with all the usual member functions and some special operators. There's also a restriction: everything must work iteratively so no nasty recursive hacks this time.
There is obviously something very wrong with the destructor of BinTreeNode class because if I delete the node like this:
BinTreeNode<int> * node = new BinTreeNode<int>();
delete node;
I can still access its data:
node->getData(); //should fail miserably
so deletion has no effect but I have no usable idea how I should correct the destructor.
It seems to me that the algorithm should be about right so I suspect there's something wrong with how I use pointers but at this point I'm so confused that I don't even understand my own code.
Code I have this far:
BinTree.h
#ifndef BINTREE_H_
#define BINTREE_H_
#ifndef NULL
#define NULL 0
#endif
#include "BinTreeNode.h"
template <class T>
class BinTree
{
private:
BinTreeNode<T> * root;
public:
//constructors and destructor
BinTree():
root(NULL){}
BinTree(T data):
root(new BinTreeNode<T>(data)){}
~BinTree();
//search
BinTreeNode<T> * search(T data);
//insert
bool insert(T data);
//remove
bool remove(T data);
};
template <class T>
BinTree<T>::~BinTree()
{
delete root;
}
template <class T>
BinTreeNode<T> * BinTree<T>::search(T data)
{
BinTreeNode<T> * node = new BinTreeNode<T>(data);
BinTreeNode<T> * current = root;
while (current != NULL)
{
if (*current == *node)
{
delete node;
return root;
}
else if (*node < *current)
{
current = current->getLeft();
}
else
{
current = current->getRight();
}
}
delete node;
return NULL;
}
template <class T>
bool BinTree<T>::insert(T data)
{
BinTreeNode<T> * node = new BinTreeNode<T>(data);
BinTreeNode<T> * current = root;
while (current != NULL)
{
if (*current == *node)
{
delete node;
return false;
}
else if (*node < *current)
{
if (current->getLeft() == NULL)
{
current->setLeft(node);
return true;
}
else
{
current = current->getLeft();
}
}
else
{
if (current->getRight() == NULL)
{
current->setRight(node);
return true;
}
else
{
current = current->getRight();
}
}
}
return false;
}
#endif
BinTreeNode.h
#ifndef BINTREENODE_H_
#define BINTREENODE_H_
#ifndef NULL
#define NULL 0
#endif
template <class T>
class BinTreeNode
{
private:
T data;
BinTreeNode<T> *left, *right, *parent;
public:
//constructors and destructor
BinTreeNode():
data(NULL), left(NULL), right(NULL), parent(NULL){}
BinTreeNode(T data):
data(data), left(NULL), right(NULL), parent(NULL){}
~BinTreeNode();
//set and get data member
T getData() const;
void setData(T data);
//set and get left and right branches
BinTreeNode<T> * getLeft() const;
BinTreeNode<T> * getRight() const;
void setLeft(BinTreeNode<T> * node);
void setRight(BinTreeNode<T> * node);
//set and get parent
BinTreeNode<T> * getParent() const;
void setParent(BinTreeNode<T> * node);
//comparison operators
bool operator<(const BinTreeNode<T>& node) const;
bool operator>(const BinTreeNode<T>& node) const;
bool operator==(const BinTreeNode<T>& node) const;
};
template <class T>
BinTreeNode<T>::~BinTreeNode()
{
BinTreeNode<T> * current = this;
BinTreeNode<T> * parent = NULL;
while (current != NULL)
{
parent = current->getParent();
if (current->getLeft() == NULL)
current = current->getLeft();
else if (current->getRight() == NULL)
current = current->getRight();
else
{
if (parent->getRight() == current)
parent->setRight(NULL);
else
parent->setLeft(NULL);
current = NULL; // this line (among others) is very suspicious
}
current = parent;
}
}
template <class T>
T BinTreeNode<T>::getData() const
{
return data;
}
template <class T>
void BinTreeNode<T>::setData(T data)
{
this->data = data;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getLeft() const
{
return left;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getRight() const
{
return right;
}
template <class T>
void BinTreeNode<T>::setLeft(BinTreeNode<T> * node)
{
node->setParent(this);
left = node;
}
template <class T>
void BinTreeNode<T>::setRight(BinTreeNode<T> * node)
{
node->setParent(this);
right = node;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getParent() const
{
return parent;
}
template <class T>
void BinTreeNode<T>::setParent(BinTreeNode<T> * node)
{
parent = node;
}
template <class T>
bool BinTreeNode<T>::operator<(const BinTreeNode<T>& node) const
{
return this->data < node.data;
}
template <class T>
bool BinTreeNode<T>::operator>(const BinTreeNode<T>& node) const
{
return this->data > node.data;
}
template <class T>
bool BinTreeNode<T>::operator==(const BinTreeNode<T>& node) const
{
return this->data == node.data;
}
#endif /* BINTREENODE_H_ */
Your BinTreeNode destructor should simply be:
template <class T>
BinTreeNode<T>::~BinTreeNode() {
delete left;
delete right;
}
That will call left and right's destructors recursively, freeing the memory allocated for those nodes and their child nodes. This will as a consequence free the entire tree.
Assigning NULL to a pointer does not free the memory pointed by it.
On the other hand, what you mention, that after deletion, this line:
node->getData();
Still returns data, is perfectly normal. Deletion frees the memory, but the data stored in it might still be available for a while, until something new is written in that memory address. Accessing an already free'd memory address implies undefined behaviour.
BTW, you should use "0"(without quotes) in C++ instead of NULL. Therefore, there it's not necessary to use the #ifndef NULL(...).
EDIT: I hadn't seen the "no recursion" comment. Here's a non-recursive algorithm:
#include <deque>
/* ... */
template <class T>
BinTreeNode<T>::~BinTreeNode() {
std::deque deq;
// we're going to delete our children
deq.push_back(this);
while(deq.size()) {
BinTreeNode<T> *ptr = deq.front();
deq.pop_front();
if(ptr) {
deq.push_back(ptr->left);
deq.push_back(ptr->right);
// we don't want the child nodes
// to double delete the children
ptr->left = 0;
ptr->right = 0;
// avoid deleteing ourselves
if(ptr != this)
delete ptr;
}
}
}
I haven't tested it, but it should work.