I'm getting the following error:
error C2371: 'BinarySearchTree::isComplete' : redefinition; different basic types
This is my header file:
#ifndef BinarySearchTree_H
#define BinarySearchTree_H
#include <iostream>
#include "Queue.h"
#include <cmath>
using namespace std;
template <class T>
struct TreeNode;
enum OrderType {PRE_ORDER, IN_ORDER, POST_ORDER};
template <class T>
class BinarySearchTree
{
public:
BinarySearchTree(); // Constructor.
~BinarySearchTree(); // Destructor.
BinarySearchTree(const BinarySearchTree& originalTree); // Copy constructor.
void operator=(const BinarySearchTree& originalTree);
void MakeEmpty();
bool IsEmpty() const;
bool IsFull() const;
int LengthIs() const;
void RetrieveItem(T& item, bool& found) const;
void InsertItem(T item);
void DeleteItem(T item);
void ResetTree(OrderType order);
void GetNextItem(T& item, OrderType order,bool& finished);
void Print(std::ostream& outFile, OrderType order) const;
int countMaxDepth();
void arrayBST(T * a);
bool isComplete();
bool isComplete(TreeNode* node);
private:
TreeNode<T>* root;
Queue<T> preQue;
Queue<T> inQue;
Queue<T> postQue;
};
template <class T>
int CountNodes(TreeNode<T>* tree);
template <class T>
void GetPredecessor(TreeNode<T>* tree, T& data);
template <class T>
void Destroy(TreeNode<T>*& tree);
template <class T>
void CopyTree(TreeNode<T>*& copy, const TreeNode<T>* originalTree);
template <class T>
void PreOrder(TreeNode<T>*, Queue<T>&);
template <class T>
void InOrder(TreeNode<T>*, Queue<T>&);
template <class T>
void PostOrder(TreeNode<T>*, Queue<T>&);
template <class T>
void PrintTree(TreeNode<T>* tree, std::ostream& outFile);
template <class T>
int maxDepth(TreeNode<T>* tree);
#endif
This is my implementation file:
#include "BinarySearchTree.h"
#include "Queue.h"
#include "Queue.cpp"
template <class T>
struct TreeNode
{
T info;
TreeNode<T>* left;
TreeNode<T>* right;
};
template <class T>
bool BinarySearchTree<T>::IsFull() const
// Returns true if the free store has no room for another node
// and false otherwise.
{
TreeNode<T>* location;
try
{
location = new TreeNode<T>;
delete location;
return false;
}
catch(std::bad_alloc exception)
{
return true;
}
}
template <class T>
bool BinarySearchTree<T>::IsEmpty() const
// Returns true if the tree is empty and false otherwise.
{
return root == NULL;
}
template <class T>
int BinarySearchTree<T>::LengthIs() const
// Calls the recursive function CountNodes to count the
// nodes in the tree.
{
return CountNodes(root);
}
template <class T>
int CountNodes(TreeNode<T>* tree)
// Post: Returns the number of nodes in the tree.
{
if (tree == NULL)
return 0;
else
return CountNodes(tree->left) + CountNodes(tree->right) + 1;
}
template <class T>
void BinarySearchTree<T>::RetrieveItem(T& item, bool& found) const
// Calls recursive function Retrieve to search the tree for item.
{
Retrieve(root, item, found);
}
template <class T>
void Retrieve(TreeNode<T>* tree,
T& item, bool& found)
// Recursively searches tree for item.
// Post: If there is an element someItem whose key matches item's,
// found is true and item is set to a copy of someItem;
// otherwise, found is false and item is unchanged.
{
if (tree == NULL)
found = false; // item is not found.
else if (item < tree->info)
Retrieve(tree->left, item, found); // Search left subtree.
else if (item > tree->info)
Retrieve(tree->right, item, found);// Search right subtree.
else
{
item = tree->info; // item is found.
found = true;
}
}
template <class T>
void BinarySearchTree<T>::InsertItem(T item)
// Calls the recursive function Insert to insert item into tree.
{
Insert(root, item);
}
template <class T>
void Insert(TreeNode<T>*& tree, T item)
// Inserts item into tree.
// Post: item is in tree; search property is maintained.
{
if (tree == NULL)
{// Insertion place found.
tree = new TreeNode<T>;
tree->right = NULL;
tree->left = NULL;
tree->info = item;
}
else if (item < tree->info)
Insert(tree->left, item); // Insert in left subtree.
else
Insert(tree->right, item); // Insert in right subtree.
}
template <class T>
void BinarySearchTree<T>::DeleteItem(T item)
// Calls the recursive function Delete to delete item from tree.
{
Delete(root, item);
}
template <class T>
void Delete(TreeNode<T>*& tree, T item)
// Deletes item from tree.
// Post: item is not in tree.
{
if (item < tree->info)
Delete(tree->left, item); // Look in left subtree.
else if (item > tree->info)
Delete(tree->right, item); // Look in right subtree.
else
DeleteNode(tree); // Node found; call DeleteNode.
}
template <class T>
void DeleteNode(TreeNode<T>*& tree)
// Deletes the node pointed to by tree.
// Post: The user's data in the node pointed to by tree is no
// longer in the tree. If tree is a leaf node or has only one
// non-NULL child pointer, the node pointed to by tree is
// deleted; otherwise, the user's data is replaced by its
// logical predecessor and the predecessor's node is deleted.
{
T data;
TreeNode<T>* tempPtr;
tempPtr = tree;
if (tree->left == NULL)
{
tree = tree->right;
delete tempPtr;
}
else if (tree->right == NULL)
{
tree = tree->left;
delete tempPtr;
}
else
{
GetPredecessor(tree->left, data);
tree->info = data;
Delete(tree->left, data); // Delete predecessor node.
}
}
template <class T>
void GetPredecessor(TreeNode<T>* tree, T& data)
// Sets data to the info member of the rightmost node in tree.
{
while (tree->right != NULL)
tree = tree->right;
data = tree->info;
}
template <class T>
BinarySearchTree<T>::BinarySearchTree()
{
root = NULL;
}
template <class T>
BinarySearchTree<T>::~BinarySearchTree()
// Calls recursive function Destroy to destroy the tree.
{
Destroy(root);
}
template <class T>
void Destroy(TreeNode<T>*& tree)
// Post: tree is empty; nodes have been deallocated.
{
if (tree != NULL)
{
Destroy(tree->left);
Destroy(tree->right);
delete tree;
}
}
template <class T>
BinarySearchTree<T>::BinarySearchTree(const BinarySearchTree<T>& originalTree)
// Calls the recursive function CopyTree to copy originalTree
// into root.
{
CopyTree(root, originalTree.root);
}
template <class T>
void BinarySearchTree<T>::operator=
(const BinarySearchTree<T>& originalTree)
// Calls the recursive function CopyTree to copy originalTree
// into root.
{
{
if (&originalTree == this)
return; // Ignore assigning self to self.
Destroy(root); // Deallocate existing tree nodes.
CopyTree(root, originalTree.root);
}
}
template <class T>
void CopyTree(TreeNode<T>*& copy,
const TreeNode<T>* originalTree)
// Post: copy is the root of a tree that is a duplicate
// of originalTree.
{
if (originalTree == NULL)
copy = NULL;
else
{
copy = new TreeNode<T>;
copy->info = originalTree->info;
CopyTree(copy->left, originalTree->left);
CopyTree(copy->right, originalTree->right);
}
}
template <class T>
void BinarySearchTree<T>::ResetTree(OrderType order)
// Calls a function to create a queue of the tree elements in
// the desired order.
{
switch (order)
{
case PRE_ORDER : PreOrder(root, preQue);
break;
case IN_ORDER : InOrder(root, inQue);
break;
case POST_ORDER: PostOrder(root, postQue);
break;
}
}
template <class T>
void PreOrder(TreeNode<T>* tree,
Queue<T>& preQue)
// Post: preQue contains the tree items in preorder.
{
if (tree != NULL)
{
preQue.Enqueue(tree->info);
PreOrder(tree->left, preQue);
PreOrder(tree->right, preQue);
}
}
template <class T>
void InOrder(TreeNode<T>* tree, Queue<T>& inQue)
// Post: inQue contains the tree items in inorder.
{
if (tree != NULL)
{
InOrder(tree->left, inQue);
inQue.Enqueue(tree->info);
InOrder(tree->right, inQue);
}
}
template <class T>
void PostOrder(TreeNode<T>* tree,
Queue<T>& postQue)
// Post: postQue contains the tree items in postorder.
{
if (tree != NULL)
{
PostOrder(tree->left, postQue);
PostOrder(tree->right, postQue);
postQue.Enqueue(tree->info);
}
}
template <class T>
void BinarySearchTree<T>::GetNextItem(T& item,
OrderType order, bool& finished)
// Returns the next item in the desired order.
// Post: For the desired order, item is the next item in the queue.
// If item is the last one in the queue, finished is true;
// otherwise, finished is false.
{
finished = false;
switch (order)
{
case PRE_ORDER : preQue.Dequeue(item);
if (preQue.IsEmpty())
finished = true;
break;
case IN_ORDER : inQue.Dequeue(item);
if (inQue.IsEmpty())
finished = true;
break;
case POST_ORDER: postQue.Dequeue(item);
if (postQue.IsEmpty())
finished = true;
break;
}
}
template <class T>
void PrintTree(TreeNode<T>* tree, std::ostream& outFile, OrderType order)
// Prints info member of items in tree in sorted order on outFile.
{
switch (order)
{
case PRE_ORDER :
if (tree != NULL)
{
outFile << tree->info;
PrintTree(tree->left, outFile ,order); // Print left subtree.
PrintTree(tree->right, outFile, order); // Print right subtree.
}
break;
case IN_ORDER :
if (tree != NULL)
{
PrintTree(tree->left, outFile, order); // Print left subtree.
outFile << tree->info;
PrintTree(tree->right, outFile, order); // Print right subtree.
}
break;
case POST_ORDER :
if (tree != NULL)
{
PrintTree(tree->left, outFile, order); // Print left subtree.
PrintTree(tree->right, outFile, order); // Print right subtree.
outFile << tree->info;
}
break;
default:;
}
}
template <class T>
void BinarySearchTree<T>::Print(std::ostream& outFile, OrderType order) const
// Calls recursive function Print to print items in the tree.
{
PrintTree(root, outFile, order);
outFile << endl;
}
template <class T>
int BinarySearchTree<T>::countMaxDepth()
{
return maxDepth(root)-1;
}
template <class T>
int maxDepth(TreeNode<T>* tree)
{
if(tree == NULL)
return 0;
else
{
int lDepth = maxDepth(tree->left);
int rDepth = maxDepth(tree->right);
if(lDepth > rDepth )
return lDepth+1;
else
return rDepth+1;
}
}
template <class T>
void BinarySearchTree<T>::arrayBST(T * a)
{
T temp;
bool f;
a = new T(CountNodes(root));
ResetTree(IN_ORDER);
for (int i = 0; i < LengthIs(); i++)
{
GetNextItem(temp, IN_ORDER, f);
a[i] = temp;
}
}
template <class T>
bool BinarySearchTree<T>::isComplete()
{
return isComplete(root);
}
template <class T>
bool BinarySearchTree<T>::isComplete(TreeNode<T>* node)
{
if (node == NULL)
return true;
if ((node->left == NULL && node->right != NULL) || (node->left != NULL && node->right == NULL))
return false;
return isComplete(node->left) && isComplete(node->right);
}
I've done some googling but it's been no use. Does anyone know what the problem is?
I think that the problem is that in the function declaration it should be:
template <class T>
class BinarySearchTree
{
public:
//...
bool isComplete(TreeNode<T>* node);
};
Or else the compiler will think it is a pointer to a non-template TreeNode type.
Maybe this non-template type does exist somewhere in your code. Or maybe you have more error messages that relate to that line. Or maybe your including of the .cpp file is messing with the linker, as the contents of that .cpp file may be compiled twice.
Do not #include one .cpp file into another.
You will have to move your class template's functions into the header from the .cpp file. See also http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html.
I see references to pointers (e.g., TreeNode<T>*&). That looks fishy.
Related
I am trying to make my inOrder function work for my test file. My function is supposed to order a string of data in a binary search tree. I expected my code to do just that but so far an only got the code to print out the root. I tried changing my function parameters to match the string of data but I'm it gives me errors. I know the algorithm is simple but I just can't figure out what parts of code go where. The code I am showing is my only attempt that runs. The code below is my Test File
#include <string>
#include "bst.h"
using namespace std;
string data[] = { "able", "baker", "charlie", "dog", "easy", "fox", "george" };
int size = 7;
binary_search_tree<string> bst1;
for (int i = 0; i < size; ++i) {
bst1.insert(data[i]);
cout << bst1 << endl;
}
cout << "balanced? " << bst1.is_balanced() << endl << endl;
bst1.inOrder(bst1.get_root());
This is my Template
#include "bst.h"
#include <string>
#include <iostream>
/**
* Add the item to this binary search tree as long as it
* is not already present.
* Return false if item is already in the tree.
* Return true if item is actually added to the tree.
*/
template <class T>
bool binary_search_tree<T>::insert(const T &item) {
root = new binary_tree_node<T>(item);
if(root == NULL)
{
insert(item);
}
if(root->data() == item)
{
return false;
}else
{
return true;
}
}
/**
* return the depth of the tree if the tree is balanced.
* Return -2 if not.
*/
template <class T>
int binary_search_tree<T>::is_balanced() {
return check_balanced(root);
}
template <class T>
std::ostream &operator<<(std::ostream &out, const binary_tree_node<T> *root) {
if(root != NULL) {
out << "[";
out << root->left() << " ";
out << root->data();
out << " " << root->right();
out << "]";
}
return out;
}
template <class T>
std::ostream &operator<<(std::ostream &out, const binary_search_tree<T> &tree) {
out << tree.root;
return out;
}
template<class T>
void binary_search_tree<T>::inOrder(binary_tree_node<T>* ptr)
{
if(ptr != NULL)
{
inOrder(ptr->left());
std::cout << ptr->data();
//if(ptr->left() != NULL && ptr->right() != NULL)
std::cout << " " ;
inOrder(ptr->right());
}
This is my HEADER
#ifndef BST_H
#define BST_H
#include "bintree.h"
#include <iostream>
template <class T>
class binary_search_tree {
public:
binary_search_tree() {
root = NULL;
}
/**
* Add the item to this binary search tree as long as it
* is not already present.
* Return false if item is already in the tree.
* Return true if item is actually added to the tree.
*/
bool insert(const T& item);
~binary_search_tree();
/**
* return the depth of the tree if the tree is balanced.
* Return -2 if not.
*/
int is_balanced();
template <class S>
friend std::ostream& operator<<(std::ostream& out, const binary_search_tree<S>& tree);
binary_tree_node<T>* get_root() { return root; }
void inOrder(binary_tree_node<T>*);
//void inOrder(const T& item);
//void inOrder();
private:
binary_tree_node<T>* root;
};
template <class T>
std::ostream& operator<<(std::ostream& out, const binary_tree_node<T>* root);
#include "bst.template"
#endif // BST_H
This Is my node Template
// FILE: bintree.template
// IMPLEMENTS: The binary_tree node class (see bintree.h for documentation).
#include <cassert> // Provides assert
#include <cstdlib> // Provides NULL, std::size_t
#include <iomanip> // Provides std::setw
#include <iostream> // Provides std::cout
template<class Process, class BTNode>
void inorder(Process f, BTNode *node_ptr)
// Library facilities used: cstdlib
{
if (node_ptr != NULL) {
inorder(f, node_ptr->left());
f(node_ptr->data());
inorder(f, node_ptr->right());
}
}
template<class Process, class BTNode>
void postorder(Process f, BTNode *node_ptr)
// Library facilities used: cstdlib
{
if (node_ptr != NULL) {
postorder(f, node_ptr->left());
postorder(f, node_ptr->right());
f(node_ptr->data());
}
}
template<class Process, class BTNode>
void preorder(Process f, BTNode *node_ptr)
// Library facilities used: cstdlib
{
if (node_ptr != NULL) {
f(node_ptr->data());
preorder(f, node_ptr->left());
preorder(f, node_ptr->right());
}
}
template<class Item, class SizeType>
void print(binary_tree_node <Item> *node_ptr, SizeType depth)
// Library facilities used: iomanip, iostream, stdlib
{
if (node_ptr != NULL) {
print(node_ptr->right(), depth + 1);
std::cout << std::setw(4 * depth) << ""; // Indent 4*depth spaces.
std::cout << node_ptr->data() << std::endl;
print(node_ptr->left(), depth + 1);
}
}
template<class Item>
void tree_clear(binary_tree_node <Item> *&root_ptr)
// Library facilities used: cstdlib
{
binary_tree_node<Item> *child;
if (root_ptr != NULL) {
child = root_ptr->left();
tree_clear(child);
child = root_ptr->right();
tree_clear(child);
delete root_ptr;
root_ptr = NULL;
}
}
template<class Item>
binary_tree_node <Item> *tree_copy(const binary_tree_node <Item> *root_ptr)
// Library facilities used: cstdlib
{
binary_tree_node<Item> *l_ptr;
binary_tree_node<Item> *r_ptr;
if (root_ptr == NULL)
return NULL;
else {
l_ptr = tree_copy(root_ptr->left());
r_ptr = tree_copy(root_ptr->right());
return
new binary_tree_node<Item>(root_ptr->data(), l_ptr, r_ptr);
}
}
template<class Item>
size_t tree_size(const binary_tree_node <Item> *node_ptr)
// Library facilities used: cstdlib
{
if (node_ptr == NULL)
return 0;
else
return
1 + tree_size(node_ptr->left()) + tree_size(node_ptr->right());
}
This is my Node Header
// FILE: bintree.h (part of the namespace main_savitch_10)
// PROVIDES: A template class for a node in a binary tree and functions for
// manipulating binary trees. The template parameter is the type of data in
// each node.
//
// TYPEDEF for the binary_tree_node<Item> template class:
// Each node of the tree contains a piece of data and pointers to its
// children. The type of the data (binary_tree_node<Item>::value_type) is
// the Item type from the template parameter. The type may be any of the C++
// built-in types (int, char, etc.), or a class with a default constructor,
// and an assignment operator.
//
// CONSTRUCTOR for the binary_tree_node<Item> class:
// binary_tree_node(
// const item& init_data = Item( ),
// binary_tree_node<Item>* init_left = NULL,
// binary_tree_node<Item>* init_right = NULL
// )
// Postcondition: The new node has its data equal to init_data,
// and it's child pointers equal to init_left and init_right.
//
// MEMBER FUNCTIONS for the binary_tree_node<Item> class:
// const item& data( ) const <----- const version
// and
// Item& data( ) <----- non-const version
// Postcondition: The return value is a reference to the data from
// this binary_tree_node.
//
// const binary_tree_node* left( ) const <----- const version
// and
// binary_tree_node* left( ) <----- non-const version
// and
// const binary_tree_node* right( ) const <----- const version
// and
// binary_tree_node* right( ) <----- non-const version
// Postcondition: The return value is a pointer to the left or right child
// (which will be NULL if there is no child).
//
// void set_data(const Item& new_data)
// Postcondition: The binary_tree_node now contains the specified new data.
//
// void set_left(binary_tree_node* new_link)
// and
// void set_right(binary_tree_node* new_link)
// Postcondition: The binary_tree_node now contains the specified new link
// to a child.
//
// bool is_leaf( )
// Postcondition: The return value is true if the node is a leaf;
// otherwise the return value is false.
//
// NON-MEMBER FUNCTIONS to maniplulate binary tree nodes:
// tempate <class Process, class BTNode>
// void inorder(Process f, BTNode* node_ptr)
// Precondition: node_ptr is a pointer to a node in a binary tree (or
// node_ptr may be NULL to indicate the empty tree).
// Postcondition: If node_ptr is non-NULL, then the function f has been
// applied to the contents of *node_ptr and all of its descendants, using
// an in-order traversal.
// Note: BTNode may be a binary_tree_node or a const binary tree node.
// Process is the type of a function f that may be called with a single
// Item argument (using the Item type from the node).
//
// tempate <class Process, class BTNode>
// void postorder(Process f, BTNode* node_ptr)
// Same as the in-order function, except with a post-order traversal.
//
// tempate <class Process, class BTNode>
// void preorder(Process f, BTNode* node_ptr)
// Same as the in-order function, except with a pre-order traversal.
//
// template <class Item, class SizeType>
// void print(const binary_tree_node<Item>* node_ptr, SizeType depth)
// Precondition: node_ptr is a pointer to a node in a binary tree (or
// node_ptr may be NULL to indicate the empty tree). If the pointer is
// not NULL, then depth is the depth of the node pointed to by node_ptr.
// Postcondition: If node_ptr is non-NULL, then the contents of *node_ptr
// and all its descendants have been written to cout with the << operator,
// using a backward in-order traversal. Each node is indented four times
// its depth.
//
// template <class Item>
// void tree_clear(binary_tree_node<Item>*& root_ptr)
// Precondition: root_ptr is the root pointer of a binary tree (which may
// be NULL for the empty tree).
// Postcondition: All nodes at the root or below have been returned to the
// heap, and root_ptr has been set to NULL.
//
// template <class Item>
// binary_tree_node<Item>* tree_copy(const binary_tree_node<Item>* root_ptr)
// Precondition: root_ptr is the root pointer of a binary tree (which may
// be NULL for the empty tree).
// Postcondition: A copy of the binary tree has been made, and the return
// value is a pointer to the root of this copy.
//
// template <class Item>
// size_t tree_size(const binary_tree_node<Item>* node_ptr)
// Precondition: node_ptr is a pointer to a node in a binary tree (or
// node_ptr may be NULL to indicate the empty tree).
// Postcondition: The return value is the number of nodes in the tree.
#ifndef BINTREE_H
#define BINTREE_H
#include <cstdlib> // Provides NULL and size_t
template <class Item>
class binary_tree_node
{
public:
// TYPEDEF
typedef Item value_type;
// CONSTRUCTOR
binary_tree_node(
const Item& init_data = Item(),
binary_tree_node* init_left = NULL,
binary_tree_node* init_right = NULL
)
{
data_field = init_data;
left_field = init_left;
right_field = init_right;
}
// MODIFICATION MEMBER FUNCTIONS
Item& data() { return data_field; }
binary_tree_node*& left() { return left_field; }
binary_tree_node*& right() { return right_field; }
void set_data(const Item& new_data) { data_field = new_data; }
void set_left(binary_tree_node* new_left) { left_field = new_left; }
void set_right(binary_tree_node* new_right) { right_field = new_right; }
// CONST MEMBER FUNCTIONS
const Item& data() const { return data_field; }
const binary_tree_node* left() const { return left_field; }
const binary_tree_node* right() const { return right_field; }
bool is_leaf() const
{
return (left_field == NULL) && (right_field == NULL);
}
private:
Item data_field;
binary_tree_node* left_field;
binary_tree_node* right_field;
};
// NON-MEMBER FUNCTIONS for the binary_tree_node<Item>:
template <class Process, class BTNode>
void inorder(Process f, BTNode* node_ptr);
template <class Process, class BTNode>
void preorder(Process f, BTNode* node_ptr);
template <class Process, class BTNode>
void postorder(Process f, BTNode* node_ptr);
template <class Item, class SizeType>
void print(binary_tree_node<Item>* node_ptr, SizeType depth);
template <class Item>
void tree_clear(binary_tree_node<Item>*& root_ptr);
template <class Item>
binary_tree_node<Item>* tree_copy(const binary_tree_node<Item>* root_ptr);
template <class Item>
std::size_t tree_size(const binary_tree_node<Item>* node_ptr);
#include "bintree.template"
#endif // BINTREE_H
From what it seems I am not getting the right variable inside my inOrder in main. I know I am following the right algorithm but I am not sure what to put for the desired result which is the sorted strings of data[] array. my code so far only prints george which is the root, but doesn't print the whole list.
When I will display the items in a queue I use the while loop
while (!queue.isEmptyQueue())
{
cout << queue.front() << " ";
queue.deleteQueue();
}
The items will be gone because of the deleteQueue() function so I cannot display it again.
How can I create a copy of the queue?
I tried the code below but it gives me errors.
queue1 = queue;
while (!queue1.isEmptyQueue())
{
cout << queue1.front() << " ";
queue1.deleteQueue();
}
I am using linkedQueue.h
#include<assert.h>
template <class Type>
struct nodeType
{
Type info;
nodeType<Type> *link;
};
template <class Type>
class linkedQueueType //: public queueADT<Type>
{
public:
const linkedQueueType<Type>& operator=(const linkedQueueType<Type>&);
bool isEmptyQueue() const;
bool isFullQueue() const;
void initializeQueue();
Type front() const;
Type back() const;
void addQueue(const Type& queueElement);
void deleteQueue();
linkedQueueType();
linkedQueueType(const linkedQueueType<Type>& otherQueue);
~linkedQueueType();
private:
nodeType<Type> *queueFront;
nodeType<Type> *queueRear;
};
template <class Type>
bool linkedQueueType<Type>::isEmptyQueue() const
{
return(queueFront == NULL);
}
template <class Type>
bool linkedQueueType<Type>::isFullQueue() const
{
return false;
}
template <class Type>
void linkedQueueType<Type>::initializeQueue()
{
nodeType<Type> *temp;
while (queueFront!= NULL)
{
temp = queueFront;
queueFront = queueFront->link;
delete temp;
}
queueRear = NULL;
}
template <class Type>
void linkedQueueType<Type>::addQueue(const Type& newElement)
{
nodeType<Type> *newNode;
newNode = new nodeType<Type>;
newNode->info = newElement;
newNode->link = NULL;
if (queueFront == NULL)
{
queueFront = newNode;
queueRear = newNode;
}
else
{
queueRear->link = newNode;
queueRear = queueRear->link;
}
}
template <class Type>
Type linkedQueueType<Type>::front() const
{
assert(queueFront != NULL);
return queueFront->info;
}
template <class Type>
Type linkedQueueType<Type>::back() const
{
assert(queueRear!= NULL);
return queueRear->info;
}
template <class Type>
void linkedQueueType<Type>::deleteQueue()
{
nodeType<Type> *temp;
if (!isEmptyQueue())
{
temp = queueFront;
queueFront = queueFront->link;
delete temp;
if (queueFront == NULL)
queueRear = NULL;
}
else
cout << "Cannot remove from an empty queue" << endl;
}
template<class Type>
linkedQueueType<Type>::linkedQueueType()
{
queueFront = NULL;
queueRear = NULL;
}
template <class Type>
linkedQueueType<Type>::~linkedQueueType()
{
initializeQueue();
}
If what you want to do is copy the queue, then a copy constructor / assignment operator is what you should have, as Martin said.
But if what you want is for the items to still be there after you go through the queue, then what your queue is missing is a way to tell how many items are in the queue.
You can cout each item and then move it to the back of the queue, that number of times.
Either way, all of these are missing for it to be a good queue implementation.
Copy constructor, assignment operator, size function.
(And technically, a queue doesn't have functionality to access the back item. So I wouldn't call this a queue with missing functionality, I would call it a linked list with missing functionality.)
Your problem is that your linkedQueueType doesn't have an assignment operator so the compiler is giving you one which just copies the pointers. You need an assignment operator which clones the elements.
This is the first time I've ever played with an iterator so there's probably significant errors. I'm attempting to make an inorder iterative iterator class to work in conjunction with my threaded binary search tree. So the iterator is working over nodes. I only need the iterator to go through my tree in order so I can print all the values and the frequencies of each node. However my dereference doesn't seem to be working probably. This is the method that's giving me trouble:
//-------------------------- inOrderTraverse ------------------------------------
template <typename T>
void ThreadedBST<T>::inOrderTraverse() {
InorderIterator<T>* iter = new InorderIterator<T>(root);
++iter;
while ((*iter) != NULL)
{
cout << (*iter)->getItem() << " " << (*iter)->getFrequency() << endl;
}
}
Particularly the while loop is throwing compiler errors. Here is the exact error:
error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'InorderIterator'
I figured the dereference would bring the node out so I'd actually be comparing the node != NULL but that's not what the error message leads me to believe. Here's the full Iterator class:
#ifndef INORDERITER_H
#define INORDERITER_H
#include <iostream>
#include "ThreadedBST.h"
using namespace std;
//---------------------------------------------------------------------------
// InorderIterator<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class InorderIterator {
public:
InorderIterator(node<T> *); //constructor
InorderIterator<T>& operator++();
node<T>& operator*();
const node<T>& operator*() const;
private:
node<T>* begin;
node<T>* curr;
node<T>* prev;
node<T>* temp;
};
template <typename T>
InorderIterator<T>::InorderIterator(node<T>* root) {
begin = root;
temp = NULL;
while (begin->leftChild != NULL) {
begin = begin->leftChild;
}
}
template <typename T>
InorderIterator<T>& InorderIterator<T>::operator++() {
if (temp == NULL)
temp = begin;
else if (rightChildThread) {
prev = temp;
temp = temp->rightChild;
}
else {
prev = temp;
temp = temp->rightChild;
while (!temp->rightChildThread && (temp->leftChild->getItem() != prev->getItem())) {
temp = temp->leftChild;
}
}
curr = temp;
return *this;
}
template <typename T>
node<T>& InorderIterator<T>::operator*() {
return *curr;
}
template <typename T>
const node<T>& InorderIterator<T>::operator*() const {
return *curr;
}
#endif
Here's the node class if it's relevant for any reason:
#ifndef NODE_H
#define NODE_H
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
// node<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class node {
public:
node<T>* leftChild;
node<T>* rightChild;
bool leftChildThread;
bool rightChildThread;
node(T value); //constructor
node(T value, node<T>*, node<T>*, bool, bool); //secondary constructor
node(const node<T>&); //copy constructor
void decrementFrequency(); //decrements by 1 the frequency
void incrementFrequency(); //increments by 1 the frequency
int getFrequency(); //returns the frequency
T getItem(); //returns the item
private:
T item;
int frequency;
};
//-------------------------- Constructor ------------------------------------
template <typename T>
node<T>::node(T value) {
item = value;
frequency = 1;
}
//-------------------------- Secondary Constructor ------------------------------------
template <typename T>
node<T>::node(T value, node<T>* left, node<T>* right, bool leftThread, bool rightThread) {
item = value;
frequency = 1;
leftChild = left;
rightChild = right;
leftChildThread = leftThread;
rightChildThread = rightThread;
}
//-------------------------- Copy ------------------------------------
template <typename T>
node<T>::node(const node<T>& copyThis) {
item = copyThis.value;
frequency = copyThis.frequency;
}
//-------------------------- decrementFrequency ------------------------------------
template <typename T>
void node<T>::decrementFrequency() {
frequency--;
}
//-------------------------- incrementFrequency ------------------------------------
template <typename T>
void node<T>::incrementFrequency() {
frequency++;
}
//-------------------------- getFrequency ------------------------------------
template <typename T>
int node<T>::getFrequency() {
return frequency;
}
//-------------------------- getItem ------------------------------------
template <typename T>
T node<T>::getItem() {
return item;
}
#endif
class const_iterator {
public:
Node *current;
const_iterator (Node *n) : current{n}
{
/* the body can remain blank, the initialization is carried
* the the constructor init list above
*/
}
/* copy assignment */
const_iterator operator= (const const_iterator& rhs) {
this->current = rhs.current;
return *this;
}
bool operator == (const const_iterator& rhs) const {
return this->current == rhs.current;
}
bool operator != (const const_iterator& rhs) const {
return this->current != rhs.current;
}
/* Update the current pointer to advance to the node
* with the next larger value
*/
const_iterator& operator++ () {
/*first step is to go left as far as possible(taken care of by begin())
once you go as left as possible, go right one step at a time*/
if(current->right != nullptr){
current = current->right;
//every step, go left again as far as possible
while(current->left != nullptr){
current = current->left;
}
}else{
bool upFromLeft = false;
bool upFromRight = false;
while(upFromLeft == false && upFromRight == false){
//if you have gone all the way up from the right
if(current->parent == nullptr){
upFromRight = true;
current = current->parent;
return *this;
}
//if you have gone all the way back up left
if(current->parent->left == current){
upFromLeft = true;
current = current->parent;
return *this;
}
current = current->parent;
}
}
return *this;
}
Z& operator *() const {
return current->data;
}
};
ADD these functions to your tree in order to use the begin() and end() with your iterator
const const_iterator begin() const {
if(rootPtr == nullptr){
return nullptr;
}
Node* temp = rootPtr;
while(temp->left != nullptr){
temp = temp->left;
}
return const_iterator(temp);
}
/* For the "end" marker
* we will use an iterator initialized to nil */
const const_iterator end() const {
return const_iterator(nullptr);
}
Here's an example of an in-order iterator I wrote in C++...
This iterator assumes that each node in your BST has a pointer to the parent node which is something I don't see in your node class. However, I am not sure its even possible to accomplish an inorder traversal without having a parent pointer.
In short, this example will work if you add a parent pointer to your nodes and update your parent pointers every time you do a node insertion or removal
I'm writing list and iterator classes function and I'm almost done, but I get some errors in the main file, that when I write the list remove_all function, but when I delete it there is no error anywhere, I don't know why!! Also, actually I'm not sure about my Iterator operators and the bool Iterator::is_item()
Any help is appreciated. Thanks
here is my codes:
Node.h
pragma once
namespace list_1
{
template <typename T>
struct Node
{
T data;
Node<T> *next;
// Constructor
// Postcondition:
Node<T> (T d);
};
template <typename T>
Node<T>::Node(T d)
{
}
}
Iterator.h
// Template CLASS PROVIDED: Iterator
#pragma once
#include "Node.h"
namespace list_1
{
template<typename T>
class Iterator
{
public:
Iterator<T> (Node<T> *np);
// precondition: is_item is true
// post condition n points to the next item in the list
void operator++();
// precondition:
// postcondition: returns true if there is a valid item
bool is_item();
// precondition: is_item == true
// postcondition returns data that n is pointing at
T operator* ();
private:
Node<T>* n;
};
List.h
#ifndef LIST_H
#define LIST_H
#include "Node.h"
#include "Iterator.h"
namespace list_1
{
template <typename T>
class list
{
public:
// CONSTRUCTOR
list( );
// postcondition: all nodes in the list are destroyed.
~list();
// MODIFICATION MEMBER FUNCTIONS
//postcondition: entry is added to the front of the list
void insert_front(const T& entry);
//postcondition: entry is added to the back of the list
void add_back(const T& entry);
// postcondition: all nodes with data == entry are removed from the list
void remove_all(const T& entry);
// postcondition: an iterator is created pointing to the head of the list
Iterator<T> begin(void);
// CONSTANT MEMBER FUNCTIONS
// postcondition: the size of the list is returned
int size( ) const;
private:
Node<T>* head;
};
Your syntax errors are because you are missing a couple closing curly brackets on your "else" blocks at the end of the remove_all function.
Try replacing it with this
(edit: included the suggestion about cout mentioned in the comments above)
void list<T>::remove_all(const T& entry)
{
if(head == 0)
{
std::cout<<" node cannot be delted";
}
else
{
Node<T> *curr = head;
Node<T> *trail = 0;
while( curr != 0)
{
if(curr->entry == entry)
{
break;
}
else
{
trail = curr;
curr = curr->next;
}
}
if(curr == 0)
{
std::cout<<" Node " << entry<< " is not found";
}
else
{
if ( head == curr)
{
head = head->next;
}
else
{
trail->next = curr->next;
}
} // missing this one
delete curr;
} // and this one as well
}
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.