I have to implement a Circularly linked queue class as the LinkedQueueType class. For some reason, when I call the enqueue function, it isn't getting added to the queue, even my test prints don't print out. Here is my queue class:
#define LINKED_QUEUE_H
class FullQueue {};
class EmptyQueue{};
typedef int ItemType;
struct NodeType{
ItemType info;
NodeType* next;
};
class LinkedQueueType {
public:
LinkedQueueType ();
// Class constructor.
// Because there is a default constructor, the precondition // that the queue has been initialized is omitted. LinkedQueueType(const LinkedQueueType& qt);
//Copy Constructor
LinkedQueueType operator=(const LinkedQueueType& rhs); //Overloaded assignment operator=
~LinkedQueueType ();
// Class destructor.
void MakeEmpty();
// Function: Initializes the queue to an empty state.
// Post: Queue is empty.
bool IsEmpty() const;
// Function: Determines whether the queue is empty.
// Post: Function value = (queue is empty)
bool IsFull() const;
// Function: Determines whether the queue is full. // Post: Function value = (queue is full)
void Enqueue(ItemType newItem);
// Function: Adds newItem to the rear of the queue. // Post: newItem is at rear of queue.
void Dequeue(ItemType& item);
// Function: Removes front item from the queue and returns it in // item.
// Post: If (queue is empty) EmptyQueue exception is thrown
// and item is undefined
// else front element has been removed from queue and
// item is a copy of removed element.
void Print(); //Print function
private:
NodeType* rear;
int length;
};
#endif
and here is the implementation for the enqueue function:
void LinkedQueueType::Enqueue(ItemType newItem){
NodeType *newNode=nullptr;
NodeType*temp=nullptr;
newNode->info=newItem;
newNode->next=nullptr;
if(rear==nullptr){
rear=newNode;
}else{
temp=rear->next;
rear->next=newNode;
}
rear=newNode;
rear->next=temp;
}
Here is my testing:
cout<<"hi";
LinkedQueueType q;
q.Enqueue(5);
When I run my driver, it doesn't print, could someone show me the way!
This is your code:
NodeType *newNode=nullptr;
NodeType*temp=nullptr;
newNode->info=newItem;
newNode->next=nullptr;
This is what you are saying:
Make a new pointer called newNode of type NodeType, and let it point to nothing.
Do the same for variable 'temp'.
Now we put newItem in nothing -> Because that is what newNode is pointing to.
Your program tries to dereference the variable newNode to access its property info. But that's not possible.
This is what your code should be:
NodeType *newNode = new NodeType();
NodeType*temp=nullptr;
newNode->info=newItem;
newNode->next=nullptr;
This way your program has an object to derefer and get a property from.
The code you posted definitely crashes (segmentation fault on Linux or access violation on Windows™) dereferencing the null pointer. You need to create the node before accessing it, like:
NodeType *newNode = new NodeType();
Related
I'm working on my final project for C++ and my professor specified that we had to have three class files for a linked list.
The first named LinkedList holds the head and the tail, as well as two overloaded operators in which we have to use the list as an array, and add an element to the end of the array.
The second named Node holds the two generic values Seat and Row.
The third and final named RNode holds the values of the next, previous spots in the list, as well as reservation status.
My problem is when using my LinkedList.cpp, defining all of the functions, I cannot figure out how to set node equal to the head, because the types are different. I can set the next node in the list with tempNode.setNext(Head);. But when I try to do tempNode = tempNode.getNext() it says the types are not the same. What is an easy way for me to make this work?
Here is my code.
This is supposed to use the Linked List as an array and return the pointer to the Node correlating with the integer passed in.
int& LinkedList::operator[] (const int &middle) {
RNode *tempNode;
tempNode->setNext(Head);
tempNode = tempNode->getNext(); // Error here
for (int i = 0; i < middle; i++) {
}
}
Here are the three class files I have currently made.
Linked List Class
#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
#include "Node.h"
class LinkedList {
private:
Node* Head; // Head of linked list
Node* Tail; // Tail of linked list
public:
// Constructors
LinkedList(); // Set default values
LinkedList(Node*, Node*); // Set values passed in to head and tail
int& operator [] (const int &); // Overloaded [] operator PAGE 854 HOW TO USE THIS
// Treat list like an array.
// First node will be [0]
// Return pointer to node indicated inside of brackets
Node& operator += (const Node &); // Overloaded += operator
// Adds a node to the end of the linked list
// Head
void setHead(Node*); // Sets head of list
Node* getHead(); // Returns the head of list
// Tail
void setTail(Node*); // Sets tail of list
Node* getTail(); // Returns tail of list
};
#endif // LINKEDLIST_H_INCLUDED
Reservation Node Class
#ifndef RNODE_H_INCLUDED
#define RNODE_H_INCLUDED
#include "Node.h"
using namespace std;
class RNode : public Node {
private:
Node* Next; // Next node pointer
Node* Prev; // Previous node pointer
bool reservationStatus(); // Reservation status
public:
// Constructors
RNode(); // Sets default values
RNode(Node*, Node*, bool); // Takes values passed in and sets them
// Overloaded operators
friend ostream &operator << (ostream &, Node*); // Prints out correct symbol based on reservation status
friend istream &operator >> (istream &, Node*); // Prints correct symbol based on reservation status .
// Next
void setNext(Node*); // Sets next node in list
Node* getNext(); // Returns next node in list
// Prev
void setPrev(Node*); // Sets previous node in list
Node* getPrev(); // Returns previous node in list
// Reservation Status
void setReservationStatus(bool); // Sets reservation status of a current node
bool getReservationStatus(); // Returns reservation status
};
#endif // RNODE_H_INCLUDED
Node Class
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
class Node {
protected:
int row;
int seat;
public:
// Constructors
Node(); // Sets default values
Node(int, int); // Sets row and seat to values passed in
// Row
void setRow(int); // Sets row for current node
int getRow(); // Gets row for current node
// Seats
void setSeat(int); // Sets seat for current node
int getSeat(); // Gets seat for current node
};
#endif // NODE_H_INCLUDED
In summary, how can I match the types so that I can set RNode tempNode equal to a Node? This is very confusing and I can't really find a good explanation on how to solve this.
Keep in mind, according to my instructions I have to have the classes created this way. If it were up to me, I would have combined the RNode and Node class.
This code is copied from the c++ primer plus. I think some
steps in the dequeue function is unnecessary. But the book
say it is important.I don't understand. I hope some one can show me more detail explanation.Here is the definition of the queue.
typedef unsigned long Item;
class Queue
{
private:
struct Node{ Item item; struct Node * next; };
enum{ Q_SIZE = 10 };
Node * front;
Node * rear;
int items; // the number of item in the queue
const int qsize;
Queue(const Queue & q) :qsize(0){};
Queue & operator=(const Queue & q){ return *this; }
Queue & operator=(const Queue & q){ return *this; }
public:
Queue(int qs = Q_SIZE);
~Queue();
bool isempty()const;
bool isfull()const;
int queuecount()const;
bool enqueue(const Item & item);
bool dequeue(Item & item);
};
bool Queue::dequeue(Item & item)
{
if (isempty())
return false;
item = front->item;
Node * temp;
temp=front; // is it necessary
front = front->next;
items--;
delete temp;
if (items == 0)
rear = NULL; //why it is not front=rear=Null ;
return true;
}
The nodes in this queue are stored as pointers. To actually create a node some code like Node* tmp = new Node() is probably somewhere in the enqueue-Function.
With front = front->next; the pointer to the first element gets moved to the next element in the queue. But what about the previous front-node? By moving the pointer we "forget" its adress, but we don't delete the object or free the memory. We have to use delete to do so, which is why the adress is temporarily stored to call the delete. Not deleting it would cause a memory leak here.
About your second question: The frontpointer has already been moved to front->next. What could that be if there was only one element inside the queue? Probably NULL, which should be ensured by the enqueue-function. ("Note: If you are managing this code, it is a good idea to replace NULL with nullptr).
The only variable that didn't get updated yet is rear.
temp = front;
saves a pointer to the front element so it can be deleted after front has been modified.
If the queue is empty, front = front->next; has already set front to null, so there's no need to do it again.
I'm getting the error no such file or directory exists and it is confusing the hell out of me. I don't want help filling in my methods or anything, that I want to do for myself. I want to fix this error so that I can get started on my project.
This is the error I get:
My Error
Here is my code where the error takes place. If you need anything else, I will gladly update my question, or provide relevant information. Thanks to anyone who helps
#ifndef _DLINKEDLIST_H_
#define _DLINKEDLIST_H_
#include <cstdlib>
#include <stdexcept>
#include <string>
using namespace std;
// template class for doubly-linked list node
template <class T>
class Node
{
public:
T data;
//string data;
Node<T>* prev;
Node<T>* next;
// default constructor
//template <class T>
Node(T value)
{
data = value;
prev = NULL;
next = NULL;
}
};
// DLinkedList class definition
template <class T>
class DLinkedList
{
private:
// DLinkedList private members
int size; // number of items stored in list
Node<T>* front; // references to the front
Node<T>* back; // and back of the list
// helper function for deep copy
// Used by copy constructor and operator=
void CopyList(const DLinkedList& ll);
// helper function for deep delete
// Used by destructor and copy/assignment
void DeleteList();
public:
// default constructor
DLinkedList();
// copy constructor, performs deep copy of list elements
DLinkedList(const DLinkedList& ll);
// destructor
~DLinkedList();
// MUTATORS
// Inserts an item at the front of the list
// POST: List contains item at position 0
// PARAM: item = item to be inserted
void InsertFront(T item);
// Inserts an item at the back of the list
// POST: List contains item at back
// PARAM: item = item to be inserted
void InsertBack(T item);
// Inserts an item in position p (0-indexed)
// Throws exception for invalid index
// PRE: 0 <= p <= size
// POST: List contains item at position p
// PARAM: item = item to be inserted, p = position where item will be inserted
void InsertAt(T item, int p);
// Removes and returns an item from position p (0-indexed)
// Throws exception if list is empty or index invalid
// PRE: 0 <= p < size
// POST: Item is removed from list
// PARAM: p = position from where item will be removed
T RemoveAt(int p);
// Removes duplicates from the list, preserving existing order of remaining items.
// The first occurrence of any duplicate (relative to the front of the list)
// is the one which remains.
// We have not yet learned about efficiency so you may implement this in any way
// as long as the resulting list satisfies the requirement above.
// PRE:
// POST: List contains no duplicates, front and back point to the appropriate nodes
// PARAM:
void RemoveDuplicates();
// ACCESSORS
// Returns size of list
int Size() const;
// Returns whether the list is empty
bool IsEmpty() const;
// Returns existence of item
bool Contains(T item) const;
// Returns item at index (0-indexed)
// Throws exception for invalid index
T ElementAt(int p) const;
// OVERLOADED OPERATORS
// overloaded assignment operator
// must work in the following cases:
// list2 = list1 -> general case
// list2 = list2 -> should do nothing
DLinkedList& operator=(const DLinkedList& ll);
};
#include "dlinkedlist.cpp"
#endif
Answer was a quick and easy #include "..\srcdlinkedlist.cpp"
instead of #include "dlinkedlist.cpp"
I am trying to make a queue implementing a linked list but am running into a compiler error. The error is coming from the overloaded assignment operator function on the line where I call the destructor (marked with an all-caps comment). I have a hunch it is a simple fix that has something to do with the syntax of my constructor/destructor declarations.
The error I am getting states the following code: error C2512: 'Queue<char>::Queue' : no appropriate default constructor available
It mentions no constructor, but the line it refers to is the one below where I am trying to call the destructor.
Thanks in advance for your help.
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
using namespace std;
template <class Type>
class Queue // Create a Queue data structure implementing a linked list
{
private: // The private members
struct Cell // The Cell class will be the blueprints for each link in the list
{
Type data; // The information held by the cell
Cell* next; // The link to the next cell
};
Cell* first = NULL;
Cell* last = NULL;
public: // The public members
Queue(Type);
bool isEmpty();
void push(Type);
Type pop();
Queue<Type>& operator=(Queue<Type>&);
friend ostream& operator<<(ostream&, const Queue<Type>&);
~Queue();
};
template<class Type>
Queue<Type>::Queue(Type inputData) // Constructor that initializes the queue with a new cell that last and first point to
{
first = new Cell;
first->data = inputData;
first->next = NULL;
last = first;
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
~Queue(); // HERE IS THE ERROR LINE
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Destructor that deallocates all of the memory used by the queue.
{
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call destructor. The list is already empty.\n";
}
}
#endif
Check out this thread: Can i call destructor from its class method?. An easy way around this is to make a function to empty the queue, then call it from the destructor and assignment operator.
template<class Type>
void Queue<Type> empty(){
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call empty. The list is already empty.\n";
}
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
empty(); // Tada, no more error
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Deconstructor that deallocates all of the memory used by the queue.
{
empty();
}
This has nothing to do with template.
If you declare any constructor for your class, the compiler synthesized default constructor(i.e. the one that takes no arg) is deleted.
You have to define Queue() yourself.
BTW, a using directive in the global scope is not a good idea.
I guess you define a queue without parameter, like
Queue<char> quCh;
If you want to do this, you must define a constructor without parameter.
Queue();
or you must define your queue like this:
Queue<char> quCh('a');
I'm writing abstract data type of priority queue as a task for an university, which others are going to use. I have a function in my class dequeue, which deletes the first element in the queue and returns the data of this element. However when I try to delete an element from an empty queue, the program crashes. What should I do here ?
Here's the code if it helps:
#ifndef PRIORITYQUEUE_H
#define PRIORITYQUEUE_H
#include <iostream>
using namespace std;
const int max_queue_items = 1000;
template<class T>
struct node{
T data;
int priority;
node *next;
};
template<class T>
class PriorityQueue
{
public:
/*
Constructor that creates an empty queue.
*/
PriorityQueue(){
head = NULL;
size = 0;
}
/*
Adds an element to the queue.
Params:
data - data of the element
priority - priority of the element
*/
bool is_empty(){
if (size == 0){
return true;
}
return false;
}
bool is_full(){
if (size == max_queue_items){
return true;
}
return false;
}
/*
Adds an element to thq queue.
It gets inserted before the first element with
lower priority.
*/
void enqueue(T data, int priority){
node<T> * previous = NULL;
node<T> * now = head;
while (now != NULL && now->priority >= priority){
previous = now;
now = now->next;
}
node<T> * new_element = new node<T>;
new_element->data = data;
new_element->priority = priority;
new_element->next = now;
if (previous == NULL){
head = new_element;
} else {
previous->next = new_element;
}
size++;
}
/*
Removes the first element in the queue
*/
T dequeue(){
T data;
if (!is_empty()){
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
}
return data;
}
/*
Returns the priority of the first element.
It's always the highest priority in the queue.
*/
int get_first_priority(){
return head->priority;
}
/*
Returns the data of the first element in the queue.
*/
T get_first_value(){
if (is_empty())
throw 0;
return head->data;
}
/*
Returns the number of elements in the queue.
*/
int get_size(){
return size;
}
/*
Deletes the whole queue from the memory.
*/
void flush(){
node<T> * now;
while (head != NULL){
now = head;
head = head->next;
delete now;
size--;
}
}
/*
Prints the whole queue following this format:
data(priority)
*/
void print(){
node<T> * now = head;
while (now != NULL){
cout << now->data << "(" << now->priority << ")" << endl;
now = now->next;
}
}
private:
node<T> * head; // Pointer to the head of the queue
int size; // Number of elements in the queue
};
#endif // PRIORITYQUEUE_H
This may or may not be the source of your problem, but I would definitely consider it an issue. In function dequeue() you are potentially returning an uninitialized variable (if T is not a class type) when is_empty() returns true:
T dequeue()
{
T data; // Uninitialized if T is not a class type
if (!is_empty())
{
node<T> * now = head;
//--------------------------------------------------------------
// This initialization is skipped when `is_empty()` returns true
data = now->data;
//--------------------------------------------------------------
head = head->next;
delete now;
size--;
}
return data;
}
Depending on what you do with the value returned by this function and on the type of T, your program might have Undefined Behavior (I can imagine T being a pointer type that you later dereference).
You may want to change the first line of the function into:
T data = T();
Which enforces value-initialization of your data object. If T is a class type, the default constructor will be invoked. Otherwise, data will be zero-initialized.
The function which calls dequeue() should then check the returned value before using it (or better, call is_empty() on the queue to check it is not empty before trying to pop a value from it).
You may even consider throwing an exception when dequeue() is invoked and the queue is empty:
T dequeue()
{
if (is_empty())
{
// Requires including the <stdexcept> standard header
throw std::logic_error("Queue is empty");
}
node<T> * now = head;
T data = now->data;
head = head->next;
delete now;
size--;
return data;
}
Clients are now responsible for making sure that dequeue() is never called on an empty queue (or they shall wrap calls to dequeue() into a try/catch block to handle the possibly thrown exception.
Another possibility is returning a bool to your client indicating whether the value was successfully popped, possibly assigning the popped element to an argument passed by reference:
bool dequeue(T& data)
{
if (is_empty())
{
return false;
}
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
return true;
}
This way, the client is responsible for checking the result of the function. If the function returns false, the data variable will be initialized to whatever the client initialized it to. Responsibilities for handling error situations is again transferred to the client.
I think there are some issues.
First and most important, there is no destructor for the class. And if not all elements are dequeued in your program there will be a memory leak. Write the destructor or use smart pointer instead of the raw one.
Second, as #Andy Prowl(btw who knows how to # people in post like twitter?) said, uninitialized local variable should be considered. And T data = T() works well both for built-in and custom types.
Third, I think there is a capacity restriction max_queue_items for the queue but there is no corresponding code for the enqueue part.
Even though, I don't think all these flaws could cause a serious crash in normal case. Maybe the problem occurs in your code invokes the class and the incorrect processing for uninitalized return value leads to a crash.
The only potential problem I see in you dequeue is that you are creating a temporary variable of the unknown type T. If you are storing data of a type with no default constructor in your priority queue, you are going to have a problem when your dequeue calls and tries to default construct that variable.
If this is the case, I would suggest that you re-work your priority queue to hold pointers to the template type rather than the data itself.