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.
Related
i'm typing my code for my assignment and i'm required to create 2 queues in the simulation file which are the customer queue and server queue which are DYNAMIC QUEUE as required in the question
i confused that whether i need to create a new queuetype in the simulation header file or i can just use the same header file
but i worry that the value between 2 queues will crashed (something like this) if i use the same header file for 2 queue
Question: Can I use the same queue ADT file for 2 different queues?
this is my code for the queue ADT header file
#ifndef H_queueAsLinkedList
#define H_queueAsLinkedList
#include <iostream>
#include <cassert>
#include "queueADT_2.h"
using namespace std;
//Definition of the node
template <class T>
struct nodeType
{
T info;
nodeType<T> *link;
};
template <class T>
class queueAsLinkedList: public queueADT<T>
{
public:
const queueAsLinkedList<T>& operator=(const queueAsLinkedList<T>&);
//Overload the assignment operator.
bool isEmpty() const;
//Function to determine whether the queue is empty.
//Postcondition: Returns true if the queue is empty,
// otherwise returns false.
bool isFull() const;
//Function to determine whether the queue is full.
//Postcondition: Returns true if the queue is full,
// otherwise returns false.
void initializeQueue();
//Function to initialize the queue to an empty state.
//Postcondition: queueFront = nullptr; queueRear = nullptr
T qFront() const;
//Function to return the first element of the queue.
//Precondition: The queue exists and is not empty.
//Postcondition: If the queue is empty, the program
// terminates; otherwise, the first
// element of the queue is returned.
T qRear() const;
//Function to return the last element of the queue.
//Precondition: The queue exists and is not empty.
//Postcondition: If the queue is empty, the program
// terminates; otherwise, the last
// element of the queue is returned.
void enQueue(const T& queueElement);
//Function to add queueElement to the queue.
//Precondition: The queue exists and is not full.
//Postcondition: The queue is changed and queueElement
// is added to the queue.
void deQueue();
//Function to remove the first element of the queue.
//Precondition: The queue exists and is not empty.
//Postcondition: The queue is changed and the first
// yelement is removed from the queue.
queueAsLinkedList();
//Default constructor
queueAsLinkedList(const queueAsLinkedList<T>& );
//Copy constructor
~queueAsLinkedList();
//Destructor
private:
nodeType<T> *queueFront; //pointer to the front of the queue
nodeType<T> *queueRear; //pointer to the rear of the queue
};
//********************implementation**************************
template <class T>
bool queueAsLinkedList<T>::isEmpty() const
{
return (queueFront == nullptr);
} //end isEmptyQueue
template <class T>
bool queueAsLinkedList<T>::isFull() const
{
return false;
} //end isFullQueue
template <class T>
void queueAsLinkedList<T>::initializeQueue()
{
nodeType<T> *temp;
while (queueFront!= nullptr) //while there are elements
//left in the queue
{
temp = queueFront; //set temp to point to the current node
queueFront = queueFront->link; //advance first to the next node
delete temp; //deallocate memory occupied by temp
}
queueRear = nullptr; //set rear to nullptr
} //end initializeQueue
template <class T>
void queueAsLinkedList<T>::enQueue(const T& newElement)
{
nodeType<T> *newNode;
newNode = new nodeType<T>; //create the node
newNode->info = newElement; //store the info
newNode->link = nullptr; //initialize the link
//field to nullptr
if (queueFront == nullptr) //if initially the queue is empty
{
queueFront = newNode;
queueRear = newNode;
}
else //add newNode at the end
{
queueRear->link = newNode;
queueRear = queueRear->link;
}
}//end enQueue
template <class T>
void queueAsLinkedList<T>::deQueue()
{
nodeType<T> *temp;
if (!isEmpty())
{
temp = queueFront; //make temp point to the first node
queueFront = queueFront->link; //advance queueFront
delete temp; //delete the first node
if (queueFront == nullptr) //if after deletion the queue is empty
queueRear = nullptr; //set queueRear to nullptr
}
else
cout << "Cannot remove from an empty queue" << endl;
}//end deQueue
template <class T>
T queueAsLinkedList<T>::qFront() const
{
assert(queueFront != nullptr);
return queueFront->info;
} //end front
template <class T>
T queueAsLinkedList<T>::qRear() const
{
assert(queueRear!= nullptr);
return queueRear->info;
} //end back
template <class T>
queueAsLinkedList<T>::queueAsLinkedList()
{
queueFront = nullptr; //set front to nullptr
queueRear = nullptr; //set rear to nullptr
} //end default constructor
template <class T>
queueAsLinkedList<T>::~queueAsLinkedList()
{
initializeQueue();
}// end Destructor
template <class T>
const queueAsLinkedList<T>& queueAsLinkedList<T>::operator=
(const queueAsLinkedList<T>& otherQueue)
{
cout << "Write the definition of the function "
<< "to overload the assignment operator." << endl;
} //end assignment operator
template <class T>
queueAsLinkedList<T>::queueAsLinkedList(const queueAsLinkedList<T>& otherQueue)
{
cout << "Write the definition of the copy constructor."
<< endl;
} //end copy constructor
#endif
sorry for my bad English, i can explain again if my description is confusing
This declaration of a queue
template <class T>
class queueAsLinkedList: public queueADT<T>
does not make a sense.
The structure nodeType
struct nodeType
{
T info;
nodeType<T> *link;
};
should be a private or protected data member of the class template queueAsLinkedList.
For example
template <class T>
class queueAsLinkedList
{
private:
struct nodeType
{
T info;
nodeType *link;
} *queueFront = nullptr, *queueRear = nullptr;
//...
You can use the same queue declaration to create two or more different objects of the queue type.
queueAsLinkedList does not have a static member.
The only thing that instances with a same class can share is static member.
Member variables are created each of Instance of class.
So you do not have to worry about crashes.
I've been given a Node and Stack class in my .h file. I have to implement the copy constructor, assignment operator and destructor and test them in a different test file. While testing the copy constructor after inserting 3 elements its displaying only one element. I don't know what's wrong; here's my .h file for your reference:
#ifndef _STACK_H
#define _STACK_H
#include <iostream>
#include <exception>
using std::ostream;
using std::cout;
using std::endl;
using std::range_error;
// Forward declarations
template <class T> class Stack;
template <class T> class Node;
template <class T> ostream& operator<<(ostream&, const Node<T>&);
// Node class for linked list
template <class T>
class Node {
friend Stack<T>;
public:
Node(T data = T(), Node<T>* next = nullptr) {
_data = data;
_next = next;
}
friend ostream& operator<< <T>(ostream& sout, const Node<T>& x);
private:
T _data;
Node* _next;
};
// Overloaded insertion operator. Must be overloaded for the template
// class T, or this won't work!
template <class T>
ostream& operator<<(ostream& sout, const Node<T>& x) {
sout << "Data: " << x._data;
return sout;
}
// Stack class. Linked-list implementation of a stack. Uses the Node
// class.
template <class T>
class Stack {
public:
// Constructor
Stack();
// Copy constructor, assignment operator, and destructor
// DO NOT IMPLEMENT HERE. SEE BELOW.
Stack(const Stack& rhs);
const Stack& operator=(const Stack& rhs);
~Stack();
void push(const T& data);
const T& top() const;
void pop();
bool empty() const; // Returns 'true' if stack is empty
void dump() const;
//Delete method used for destructor
void nullify();
private:
Node<T>* _head;
Node<T>* _temp1;
Node<T>* _temp2; //pointers
};
template <class T>
Stack<T>::Stack() {
_head = nullptr;
}
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) {
if (rhs._head != nullptr) {
_head = new Node<T>(rhs._head->_data);
_temp1 = _head->_next; //temp1 would be the next one after head
//_temp2 = _temp2->_next;
while (_temp2 != nullptr) {
_temp1 = new Node<T>(_temp2->_data);
_temp1 = _temp1->_next;
_temp2 = _temp2->_next; //temp2 should be the next node after temp1
}
}
else
_head = nullptr;
}
template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
if (this != &rhs) {
nullify();
if (rhs._head != nullptr) {
_head = new Node<T>(rhs._head->_data);
_temp1 = _head->_next; //temp1 would be the next one after head
//_temp2 = _temp2->_next;
while (_temp2 != nullptr) {
_temp1 = new Node<T>(_temp2->_data);
_temp1 = _temp1->_next;
_temp2 = _temp2->_next; //temp2 should be the next node after temp1
}
}
else
_head = nullptr;
}
return *this;
}
template <class T>
Stack<T>::~Stack() {
nullify();
}
template <class T>
void Stack<T>::nullify() {
while (!empty()) {
pop();
}
}
template <class T>
void Stack<T>::pop() {
if (empty()) {
throw range_error("Stack<T>::pop(): attempt to pop from an empty stack.");
}
Node<T>* tmpPtr = _head->_next;
delete _head;
_head = tmpPtr;
}
template <class T>
bool Stack<T>::empty() const {
return _head == nullptr;
}
template <class T>
void Stack<T>::push(const T& data) {
Node<T>* tmpPtr = new Node<T>(data);
tmpPtr->_next = _head;
_head = tmpPtr;
}
template <class T>
const T& Stack<T>::top() const {
if (empty()) {
throw range_error("Stack<T>::top(): attempt to read empty stack.");
}
return _head->_data;
}
template <class T>
void Stack<T>::dump() const {
Node<T>* nodePtr = _head;
while (nodePtr != nullptr) {
cout << nodePtr->_data << endl;
nodePtr = nodePtr->_next;
}
}
#endif
While pushing 34, 67, 92 it shows only 92 for the copy constructor during output. Here's the code for which I'm testing my .h code:
#include "stack.h"
#include <iostream>
using namespace std;
using std::cout;
using std::endl;
int main()
{
cout << "Testing default constructor\n";
Stack<int> intStack;
intStack.dump();
cout << "Stack is empty initially\n\n";
intStack.push(34);
intStack.push(67);
intStack.push(92);
cout << "Testing copy constructor after inserting 92, 67 & 34: \n";
Stack<int> test1(intStack);
//cout << "Dumping intStack into Test1 & displaying it: \n";
test1.dump();
cout << "\nTesting destructor: \n";
test1.nullify();
test1.dump();
cout << "Its empty\n\n";
Stack<int> test2;
test2.push(75);
test2.push(56);
test2.push(88);
test2.push(69);
cout << "Testing assignment operator after inserting 69, 88, 56 & 75: \n";
Stack<int> test3;
test3 = test2;
test3.dump();
cout << "\nTesting destructor: \n";
test2.nullify();
test2.dump();
cout << "Its empty\n\n";
return 0;
}
I'm still not used to C++ completely so sorry for any errors.
There are several things wrong with your Stack class.
First, the copy constructor doesn't initialize all the members, and neither does your default constructor. Those need to be fixed:
template <class T>
Stack<T>::Stack() : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {}
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr)
{
//...
}
Once this is done, the copy constructor can be easily implemented using your other existing function, Stack::push. Your implementation is way too complicated.
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
Node<T>* temp = rhs._head;
while (temp)
{
push(temp->_data);
temp = temp->_next;
}
}
What is being done here? Simple -- all we are doing is taking the head of the passed-in Stack, and looping over the items calling Stack::push to add the data to the new Stack object. Since you have a push function already coded, you should be using it.
Second, note that we use a local temp variable. I doubt you need any of those _temp members in your class, but that is a different story.
Last, your assignment operator can easily be implemented, given you have a copy constructor and destructor for Stack:
template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
if (this != &rhs) {
Stack<T> temp = rhs;
std::swap(temp._head, _head);
std::swap(temp._temp1, _temp1);
std::swap(temp._temp2, _temp2);
}
return *this;
}
That technique uses copy / swap. All that is being done is to create a temporary from the passed-in Stack object, and just swap out the current contents with the temporary's contents. Then the temporary dies off with the old contents.
Given all of this, the class should work correctly. Whether it is 100% correct with all of the other functions, that again is a different issue.
Edit:
Here is a fix for the copy constructor. Note we still use existing functions to make the copy:
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
Node<T>* temp = rhs._head;
Stack<T> tempStack;
while (temp)
{
tempStack.push(temp->_data);
temp = temp->_next;
}
while (!tempStack.empty())
{
push(tempStack.top());
tempStack.pop();
}
}
This is not as efficient, but usually a stack data structure uses an underlying container such as vector where it is easy to reverse the underlying contents, and not based on a singly linked-list as you're using.
I am attempting to make a queue in c++ using a double linked list. I Have not fully tested everything since i am stuck at the step where you dequeue. I attempted to create a temp node, and move around stuff so when I call delete on the head node in the queue (called queue), and then set the head to a temp node which is the next element, (you can see in the code) but when I call delete, is where it crashes, according to MS Visual studios 2013. Also to add how weird this is, following the stack called, after delete is called, setPrev is called and set the prev node and crashes there. Now I never call this function during any of my destructors deletes so any help will do. I will try my best to understand any answers but I am still new to c++ terminology. Below is my code. Oh one last thing, in main, all I did was call enqueue once, then dequeue once, then delete
Node Class
...
#ifndef TSDNODE_H
#define TSDNODE_H
template <class T>
class DNode
{
private:
DNode<T>* next;
DNode<T>* prev;
T data;
public:
DNode(T);
void setNext(DNode<T>* next);
void setPrev(DNode<T>* prev);
DNode<T>* getNext() const;
DNode<T>* getPrev() const;
T getData() const;
void setData(T data);
~DNode();
};
template <class T>
DNode<T>::DNode(T data)
{
this->next = nullptr;
this->data = data;
this->prev = nullptr;
}
template <class T>
void DNode<T>::setNext(DNode<T>* next)
{
this->next = next;
}
template <class T>
void DNode<T>::setPrev(DNode<T>* prev)
{
this->prev = prev;
}
template <class T>
DNode<T>* DNode<T>::getNext() const
{
return this->next;
}
template <class T>
DNode<T>* DNode<T>::getPrev() const
{
return this->prev;
}
template <class T>
T DNode<T>::getData() const
{
return this->data;
}
template <class T>
void DNode<T>::setData(T data)
{
this->data = data;
}
template <class T>
DNode<T>::~DNode()
{
delete this->next;
delete this->prev;
this->next = nullptr;
this->prev = nullptr;
}
#endif /* TSDNODE_H */
....
Queue Class
....
#ifndef TSQUEUE_H
#define TSQUEUE_H
#include "TSDNode.h"
#include <string>
template <class T>
class Queue
{
private:
DNode<T>* queue;
DNode<T>* tail;
int size;
public:
Queue();
void enqueue(T data);
T dequeue();
~Queue();
};
template <class T>
Queue<T>::Queue()
{
this->queue = nullptr;
this->tail = this->queue;
size = 0;
}
template <class T>
void Queue<T>::enqueue(T data)
{
if (this->tail != NULL)
{
this->tail->setNext(new DNode<T>(data));
this->tail->getNext()->setPrev(this->tail);
this->tail = this->tail->getNext();
}
else
{
this->queue = new DNode<T>(data);
this->tail = this->queue;
}
size++;
}
template <class T>
T Queue<T>::dequeue()
{
T data;
if (this->queue == nullptr)
{
delete this->tail;
delete this->queue;
this->tail = nullptr;
std::string ex = "Exception: Empty Queue\n";
throw ex;
}
else if (this->queue != nullptr)
{
data = this->queue->getData();
DNode<T>* node = this->queue->getNext();
this->queue->setNext(nullptr);
this->queue->setPrev(nullptr);
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
delete this->queue;
this->queue = node;
}
size--;
return data;
}
template <class T>
Queue<T>::~Queue()
{
delete this->queue;
this->queue = nullptr;
this->tail = nullptr;
}
#endif /* TSQUEUE_H */
In your DNode destructor, you don't want to delete the next and prev nodes. You only want to delete this node, not everything it links to.
Remove these lines
delete this->next;
delete this->prev;
Edit: Actually this isn't your problem, because you are clearing out the next and prev values before you delete the node. I still think it is better to not automatically delete the whole chain, but as long as you are consistent with how you handle node deletion it should still work.
You actually problem is that when you dequeue the last node, you still try to set the next pointer of the next node in this line:
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
At this point node is nullptr, so trying to access node->next causes a crash. A simple if test is all you need
if (node != nullptr)
node->setPrev(nullptr);
//--------------------------------------------------- no longer crashes here
Edit 2:
Also note that in the case where the next node in the queue is nullptr, you also want to set the tail to nullptr.
I am having some trouble with my homework and could use your help.
I am getting some sort of error when I try to run my program. When i compile it i get the success mssage but when i try to run it i get a popup with the error "Unhandled exception at 0x011b18d2 in Project 2.exe: 0xC0000005: Access violation reading location 0xccccccd0." If anyone can help me i would appreciate it, thank you.
This is the code i was assigned to build on (this cannot be changed)
#include <iostream >
#include "stack.h"
using namespace std ;
int main ()
{
Stack < int > s1 , s2 ;
int element ;
s1 . push (1); s1 . push (2); s1 . push (3);
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 = s1 ;
s2 . push (4);
s2 . pop ( element );
cout << " s2 popped element : " << element << endl ;
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 . makeEmpty ();
s2 . isEmpty () ? cout << " s2 is empty \n": cout << " s2 is not empty \n ";
system ("pause");
return 0;
}
This is what i wrote to compliment the code above
template <class DataType>
struct Node{
DataType info;
Node<DataType>*next;
};
template <class DataType>
class Stack
{
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType & poppedElement);
bool peek(DataType & topElement);
Stack(const Stack<DataType> &element); // Copy constructor
~Stack(); // Destructor
Stack<DataType> & operator=(const Stack<DataType> &element); //Overload assignment operator
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>*top;
Node<DataType>*header;
inline void deepCopy(const Stack<DataType> & original);
};
template<class DataType>
Stack<DataType>::Stack()
{
Node<DataType>*top=new Node<DataType>;
}
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType & poppedElement)
{
Node<DataType>*ptr=top;
ptr=ptr->next;
Node<DataType>*ptr2=ptr->next;
top->next=ptr2;
poppedElement = ptr->info;
delete ptr;
return true;
}
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType & topElement)
{
if(top->next==NULL)
return false;
topElement=top->next->info;
return true;
}
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush)
{
Node<DataType>*ptr=top;
Node<DataType>*ptr2=new Node<DataType>;
ptr2->info=elementToPush;
ptr2->next=ptr->next;
ptr->next=ptr2;
}
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const
{
return top->next==NULL;
}
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty()
{
Node<DataType>*ptr=top;
while(top->next != NULL)
{
while(ptr->next != NULL)
ptr->next;
delete ptr->next;
}
}
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType> & original)
{
Node<DataType>*copyptr=new Node<DataType>;
Node<DataType>*originalptr=top;
while(originalptr != NULL)
{
originalptr=originalptr->next;
copyptr->next=new Node<DataType>;
copyptr->info=originalptr->info;
}
}
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType> &element)
{
deepCopy(element);
}
template<class DataType> // Destructor
Stack<DataType>::~Stack()
{
makeEmpty();
}
template<class DataType> // Overload assignment operator
Stack<DataType> & Stack<DataType>::operator=(const Stack<DataType> &element)
{
if(this == &element)
return *this;
makeEmpty();
deepCopy(element);
return *this;
}
I got pushback on my previous answer. Maybe this one will be better received. If you don't like my choice of white space, that is what pretty-printers are for. The code below is the original code reformatted. My thoughts are included as interlinear gloss.
Node is an implementation detail of your Stack. It should be scoped as a private type declaration, putting here pollutes the namespace. Also, if this class had a constructor that either initialized next to nullptr or required it to be set explicitly, some bugs, such as the one you found, would be easier to diagnose. As it stands, after Node is constructed, next can point to a random memory location.
template <class DataType>
struct Node {
DataType info;
Consider using a smart pointer here.
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
The argument should be const& to avoid extra copying.
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
This can be a const method.
bool peek(DataType& topElement);
element is a poor name. The copy constructor copies an entire stack, not just an element.
Stack(const Stack<DataType>& element); // Copy constructor
~Stack(); // Destructor
Stack<DataType>& operator=(const Stack<DataType>&
element); //Overload assignment operator
bool isEmpty() const;
void makeEmpty();
private:
Consider using a smart pointer here.
Node<DataType>* top;
header is not used. It should be deleted.
Node<DataType>* header;
inline void deepCopy(const Stack<DataType>& original); };
template<class DataType>
Stack<DataType>::Stack() {
top should be initialized to nullptr in a member initialization list. The empty node you
are using here is not required, it makes you code more complex, and you end up leaking it later.
Also, this is a major bug. You are assigning to a local here, not the member variable!
Node<DataType>* top = new Node<DataType>; }
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType& poppedElement) {
If you want ptr to be top->next just say that.
Node<DataType>* ptr = top;
ptr = ptr->next;
This ptr2 variable is not needed. You just need top->next = top->next->next. Also note that the empty head element is adding noise here.
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
You need to have tested for underflow to return false in that case.
return true; }
People are pretty forgiving about comments, but it is best if they are properly spelled and punctuated.
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush) {
This variable is meaningless, just use top.
Node<DataType>* ptr = top;
ptr2 can be constructed with the values you need instead of being mutated afterwards. Try auto ptr2 = new Node<DataType> { elementToPush, ptr->next };. Also, consider using a smart pointer.
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = ptr->next;
ptr->next = ptr2; }
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
This function is just broken. You need to rethink it.
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty() {
Node<DataType>* ptr = top;
while (top->next != NULL) {
One while loop will do you. Lists are linear, not square.
while (ptr->next != NULL) {
This statement has no effect; it does nothing. Your compiler should be warning about that, turn on warnings, or turn the warning level up.
ptr->next; }
delete ptr->next; } }
This is very broken too. You need to iterate over two lists, so you need two iterator variables. One iterator is the stuff you are copying and just needs to be bumped along as you read it. The other is mutating the current object and has slightly more book keeping.
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* copyptr = new Node<DataType>;
Node<DataType>* originalptr = top;
while (originalptr != NULL) {
originalptr = originalptr->next;
copyptr->next = new Node<DataType>;
copyptr->info = originalptr->info; } }
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
template<class DataType> // Destructor
Stack<DataType>::~Stack() {
Note that makeEmpty does not delete your empty head node. This will leak a node.
makeEmpty(); }
template<class DataType> // Overload assignment operator
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
Again, your empty head node is causing pain here. Does deepCopy create the empty head node or not? Your use of it in your copy constructor seems to assume it does. Your use of it here seems to assume it does not. In fact, I think the problem is that makeEmpty does not delete your head node, if it did, both this function and your destructor would work properly.
deepCopy(element);
return *this; }
What you are seeing is a run-time error, not a build error. And your IDE reports a successful build, not your debugger. Your debugger is what allows you to trace through the program line-by-line and inspect the values of your variables.
Compare your code to the following.
template <class DataType>
struct Node {
DataType info;
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
bool peek(DataType& topElement);
Stack(const Stack<DataType>& element);
~Stack();
Stack<DataType>& operator=(const Stack<DataType>& element);
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>* top;
inline void deepCopy(const Stack<DataType>& original); };
// Linked list stack implementation.
template<class DataType>
Stack<DataType>::Stack() {
// Head of the list. Not actually used for anything. Why is this here?
top = new Node<DataType>; }
// Remove the node at the front of the list and return the element
// Does not check for underflow.
template<class DataType>
bool Stack<DataType>::pop(DataType& poppedElement) {
Node<DataType>* ptr = top->next;
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
return true; }
// Return the element at the front of the list without deleting it
template<class DataType>
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
// Make a new node for the element and push it to the front of the list
template<class DataType>
void Stack<DataType>::push(DataType elementToPush) {
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = top->next;
top->next = ptr2; }
// Check to see if the list is empty
template<class DataType>
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
// Empty the list out
template<class DataType>
void Stack<DataType>::makeEmpty() {
while (top->next != NULL) {
Node<DataType>* ptr = top->next;
top->next = ptr->next;
delete ptr; } }
// Deep copy
template<class DataType>
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* origiter = original.top;
Node<DataType>* thisiter = top;
while (origiter->next != NULL) {
thisiter->next = new Node<DataType>(*(origiter->next));
origiter = origiter->next;
thisiter = thisiter->next; }
thisiter->next = NULL; }
// Copy Constructor
template<class DataType>
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
// Destructor
template<class DataType>
Stack<DataType>::~Stack() {
// This leaks because the head node is still there.
makeEmpty(); }
// Overload assignment operator
template<class DataType>
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
deepCopy(element);
return *this; }
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.