I created a class for queue an I'm using an object of that class in a loop. After an iteration the value of the first element in queue change to a residual value. Why is that and how can I fix it?
Here's the .h file:
#ifndef QUEUE_H
#define QUEUE_H
#include "headers.h"
template <class T>
class Queue
{
public:
Queue();
~Queue();
void Push(T value); // Insert a new element at the end of the queue.
void Display(); // Display the queue.
T Pop(); // Delete the top of the queue and returns it.
T Peek(); // Returns the top of the queue.
T GetPositionValue(uint pos); // Returns the value found on the specified position.
T GetMin(); // Returns the lowest value in the queue.
T GetMax(); // Returns the highest value in the queue.
uint Distance(T value); // Returns -1 if the value isn't in the queue, else returns the distance from the top.
uint GetSize() const { return size; } // Returns the number of elements found in the stack.
bool IsEmpty() { return (first == nullptr); } // Returns true if the queue is empty.
bool HasValue(T value); // Returns true if the value is in the queue.
bool HasPosition(uint pos); // Returns true if pos is found in queue. Position 0 is top.
private:
struct Node
{
T value;
Node *next;
};
Node *first, *last;
uint size;
Node *GetPositionAddress(uint pos);
Node *GetValueAddress(T value);
};
template <class T>
class Deque
{
public:
Deque();
~Deque();
void PushBack(T value);
void PushFront(T value);
void Display();
T PopFront();
T PeekFront();
T PopEnd();
T PeekEnd();
T GetPositionValue(uint pos);
T GetMin();
T GetMax();
uint Distance(T value);
uint GetSize() const { return size; }
bool IsEmpty() { return (first == nullptr); }
bool HasValue(T value);
bool HasPosition(uint pos);
private:
struct Node
{
T value;
Node *next;
};
Node *first, *last;
uint size;
Node *GetPositionAddress(uint pos);
Node *GetValueAddress(T value);
};
#include "Queue.cpp"
#endif
Here's where the queue is used.
#include "../Headers/queue.h"
// Simple linked list of queues
struct SLLQ
{
Deque<int> deq;
SLLQ *next;
};
void CreateStorage(SLLQ *&head, SLLQ *&tail)
{
SLLQ *elem = new SLLQ;
elem->next = NULL;
if (!head)
{
head = elem;
tail = elem;
}
else
{
tail->next = elem;
tail = elem;
}
}
int main()
{
std::ifstream f("Inputs/hw4p7.in");
int k, k2, n;
Queue<int> laneIN, laneOUT;
SLLQ *sqf = NULL, *sql = NULL;
f >> k;
k2 = k;
f >> n;
for (int i = 0; i < n; i++)
{
int value;
f >> value;
laneIN.Push(value);
}
k--;
CreateStorage(sqf, sql);
sqf->deq.PushBack(laneIN.Pop());
// Inserting the wagons in the storage lines
for (int i = 1; i < n; i++)
{
if (sqf->deq.PeekEnd() < laneIN.Peek())
sqf->deq.PushBack(laneIN.Pop());
else
{
SLLQ *temp = sqf;
bool pushed = false;
while (!pushed)
{
if (!temp->next)
{
// End the program if he use to much storage lanes
if (!k)
{
std::cout << "There's no strategy with " << k2 << " storage lanes.";
_getch();
return;
}
k--;
CreateStorage(sqf, sql);
temp = temp->next;
temp->deq.PushBack(laneIN.Pop());
pushed = true;
}
else
{
temp = temp->next;
if (temp->deq.PeekEnd() < laneIN.Peek())
{
temp->deq.PushBack(laneIN.Pop());
pushed = true;
}
}
}
}
}
// Inserting the wagons in the out lane
for (int i = 0; i < n; i++)
{
SLLQ *temp = sqf;
Deque<int> mina = temp->deq;
temp = temp->next;
while (temp)
{
if (temp->deq.PeekFront() < mina.PeekFront())
mina = temp->deq;
temp = temp->next;
}
SLLQ *minadd = sqf;
SLLQ *predminadd = sqf;
while (minadd && (minadd->deq.PeekFront() != mina.PeekFront()))
{
minadd = minadd->next;
if (predminadd->next != minadd)
predminadd = predminadd->next;
}
laneOUT.Push(minadd->deq.PopFront());
if (minadd->deq.IsEmpty())
{
delete minadd;
predminadd->next = nullptr;
}
}
laneOUT.Display();
_getch();
return 0;
}
Here's the .cpp file with queue members definitions:
#include "queue.h"
template<class T>
Queue<T>::Queue()
{
first = last = nullptr;
size = 0;
}
template<class T>
Queue<T>::~Queue()
{
while (first)
{
typename Queue<T>::Node *del = first;
first = first->next;
delete del;
}
first = last = nullptr;
size = 0;
}
template <class T>
void Queue<T>::Push(T value)
{
typename Queue<T>::Node *elem = new Node;
elem->value = value;
elem->next = nullptr;
if (first)
last->next = elem;
else
first = elem;
last = elem;
size++;
}
template <class T>
void Queue<T>::Display()
{
typename Queue<T>::Node *temp = first;
while (temp)
{
std::cout << temp->value << "\n";
temp = temp->next;
}
}
template <class T>
T Queue<T>::Pop()
{
if (IsEmpty())
return T(-1);
T value = first->value;
typename Queue<T>::Node *temp = first;
first = first->next;
delete temp;
if (first == nullptr)
last = nullptr;
size--;
return value;
}
template <class T>
T Queue<T>::Peek()
{
if (IsEmpty())
return T(-1);
return first->value;
}
template <class T>
T Queue<T>::GetPositionValue(uint pos)
{
if (IsEmpty() || !HasPosition(pos))
return T(-1);
typename Queue<T>::Node *temp = first;
for (uint i = 1; i < pos; i++)
temp = temp->next;
return temp->value;
}
template <class T>
uint Queue<T>::Distance(T value)
{
uint distance = 0;
if (!HasValue(value))
return -1;
typename Queue<T>::Node *temp = first;
while (temp && temp->value != value)
{
temp = temp->next;
distance++;
}
return distance;
}
template <class T>
T Queue<T>::GetMin()
{
if (IsEmpty())
return T();
T min = first->value;
typename Queue<T>::Node *temp = first;
while (temp->next)
{
temp = temp->next;
if (temp->value < min)
min = temp->value;
}
return min;
}
template <class T>
T Queue<T>::GetMax()
{
if (IsEmpty())
return T();
T max = first->value;
typename Queue<T>::Node *temp = first;
while (temp->next)
{
temp = temp->next;
if (temp->value > max)
max = temp->value;
}
return max;
}
template <class T>
bool Queue<T>::HasValue(T value)
{
typename Queue<T>::Node *temp = first;
while (temp && temp->value != value)
temp = temp->next;
if (!temp)
return false;
else
return true;
}
template <class T>
bool Queue<T>::HasPosition(uint pos)
{
if (IsEmpty())
return false;
uint i = 1;
typename Queue<T>::Node *temp = first;
while (temp && i < pos)
{
temp = temp->next;
i++;
}
if (i == pos)
return true;
else
return false;
}
// Private members
template <class T>
typename Queue<T>::Node *Queue<T>::GetPositionAddress(uint pos)
{
if (IsEmpty() || !HasPosition(pos))
return nullptr;
Node *temp = first;
for (uint i = 1; i < pos; i++)
temp = temp->next;
return temp;
}
template <class T>
typename Queue<T>::Node *Queue<T>::GetValueAddress(T value)
{
if (IsEmpty() || !HasValue(value))
return nullptr;
Node *temp = first;
while (temp->value != value)
temp = temp->next;
return temp;
}
// Deque
template <class T>
Deque<T>::Deque()
{
first = last = nullptr;
size = 0;
}
template <class T>
Deque<T>::~Deque()
{
while (first)
{
typename Deque<T>::Node *del = first;
first = first->next;
delete del;
}
first = last = nullptr;
size = 0;
}
template <class T>
void Deque<T>::PushBack(T value)
{
typename Deque<T>::Node *elem = new Node;
elem->value = value;
elem->next = nullptr;
if (first)
last->next = elem;
else
first = elem;
last = elem;
size++;
}
template <class T>
void Deque<T>::PushFront(T value)
{
typename Deque<T>::Node *elem = new Node;
elem->value = value;
elem->next = nullptr;
if (first)
elem->next = first;
else
last = elem;
first = elem;
size++;
}
template <class T>
void Deque<T>::Display()
{
typename Deque<T>::Node *temp = first;
while (temp)
{
std::cout << temp->value << "\n";
temp = temp->next;
}
}
template <class T>
T Deque<T>::PopFront()
{
if (IsEmpty())
return T(-1);
T value = first->value;
typename Deque<T>::Node *temp = first;
first = first->next;
delete temp;
if (first == nullptr)
last = nullptr;
size--;
return value;
}
template <class T>
T Deque<T>::PeekFront()
{
if (IsEmpty())
return T(-1);
return first->value;
}
template <class T>
T Deque<T>::PopEnd()
{
if (IsEmpty())
return T(-1);
if (first == last)
return PopFront();
T value = last->value;
typename Deque<T>::Node *temp = first;
while (temp && temp->next != last)
temp = temp->next;
delete last;
last = temp;
size--;
return value;
}
template <class T>
T Deque<T>::PeekEnd()
{
if (IsEmpty())
return T(-1);
return last->value;
}
template <class T>
T Deque<T>::GetPositionValue(uint pos)
{
if (IsEmpty() || !HasPosition(pos))
return T(-1);
typename Deque<T>::Node *temp = first;
for (uint i = 1; i < pos; i++)
temp = temp->next;
return temp->value;
}
template <class T>
uint Deque<T>::Distance(T value)
{
uint distance = 0;
if (!HasValue(value))
return -1;
typename Deque<T>::Node *temp = first;
while (temp && temp->value != value)
{
temp = temp->next;
distance++;
}
return distance;
}
template <class T>
T Deque<T>::GetMin()
{
if (IsEmpty())
return T();
T min = first->value;
typename Deque<T>::Node *temp = first;
while (temp->next)
{
temp = temp->next;
if (temp->value < min)
min = temp->value;
}
return min;
}
template <class T>
T Deque<T>::GetMax()
{
if (IsEmpty())
return T();
T max = first->value;
typename Deque<T>::Node *temp = first;
while (temp->next)
{
temp = temp->next;
if (temp->value > max)
max = temp->value;
}
return max;
}
template <class T>
bool Deque<T>::HasValue(T value)
{
typename Deque<T>::Node *temp = first;
while (temp && temp->value != value)
temp = temp->next;
if (!temp)
return false;
else
return true;
}
template <class T>
bool Deque<T>::HasPosition(uint pos)
{
if (IsEmpty())
return false;
uint i = 1;
typename Deque<T>::Node *temp = first;
while (temp && i < pos)
{
temp = temp->next;
i++;
}
if (i == pos)
return true;
else
return false;
}
// Private members
template <class T>
typename Deque<T>::Node *Deque<T>::GetPositionAddress(uint pos)
{
if (IsEmpty() || !HasPosition(pos))
return nullptr;
Node *temp = first;
for (uint i = 1; i < pos; i++)
temp = temp->next;
return temp;
}
template <class T>
typename Deque<T>::Node *Deque<T>::GetValueAddress(T value)
{
if (IsEmpty() || !HasValue(value))
return nullptr;
Node *temp = first;
while (temp->value != value)
temp = temp->next;
return temp;
}
The problem is at line 114(third for) where the queue is used, precisely: "laneOUT.Push(minadd->deq.PopFront());"
It puts the value in laneOUT but at next iteration it changes to a residual value.
After almost three years I came across this old question of mine and remembered I wasn't able to fix this code back then, so I thought I would give it a try now that I know so much more.
A big no no can be spotted right away in the second statement of the third for-loop from the main function:
Deque<int> mina = temp->deq;
This code performs a copy, but the Deque class has no copy-constructor implemented explicitly although it manage resources.
The implicit copy-constructor will perform a shallow copy and after the first iteration of the for-loop, the mina object will be destroyed but the memory deallocated is still pointed to by temp->deq used to initialize mina, in the first iteration, without any knowledge that the memory it points to is deallocated.
The Rule of Three (Five in C++11) must be respected when a class manages resources.
Related
I have a utility library that I developed and noticed I have a memory leak in the SinglyLinkedList class. After debugging the code, I could not find why I have a memory leak. This is the test case I am using in the main function:
#include <iostream>
#include "SinglyLinkedList.h"
using namespace std;
int main() {
cout << "Program operating..." << endl;
do {
SinglyLinkedList<int> list = SinglyLinkedList<int>();
list.add(1);
list.add(1);
list.add(1);
} while (true);
cout << "Program terminated..." << endl;
}
Here is SinglyLinkedList.h file. It contains the SinglyLinkedNode and SinglyLinkedList class.
#pragma once
// SinglyLinkedNode
template <class T>
class SinglyLinkedNode {
public:
T data;
SinglyLinkedNode<T>* nextNode;
SinglyLinkedNode(T data);
SinglyLinkedNode(const SinglyLinkedNode& singlyLinkedNode);
void operator = (const SinglyLinkedNode& singlyLinkedNode);
~SinglyLinkedNode();
};
template <class T>
SinglyLinkedNode<T>::SinglyLinkedNode(T data) {
this->data = data;
nextNode = nullptr;
}
template <class T>
SinglyLinkedNode<T>::SinglyLinkedNode(const SinglyLinkedNode& singlyLinkedNode) {
this->data = singlyLinkedNode.data;
nextNode = nullptr;
}
template <class T>
void SinglyLinkedNode<T>::operator = (const SinglyLinkedNode& singlyLinkedNode) {
this->data = singlyLinkedNode.data;
nextNode = nullptr;
}
template <class T>
SinglyLinkedNode<T>::~SinglyLinkedNode() {
nextNode = nullptr;
}
// SinglyLinkedList
template <class E>
class SinglyLinkedList {
private:
unsigned int size;
public:
SinglyLinkedNode<E>* head;
SinglyLinkedNode<E>* tail;
SinglyLinkedList();
SinglyLinkedList(const SinglyLinkedList& singlyLinkedList); // O(n)
void operator = (const SinglyLinkedList<E> singlyLinkedList); // O(n)
SinglyLinkedNode<E>* add(E data); // O(1)
SinglyLinkedNode<E>* addAt(unsigned int i, E data); // O(n)
SinglyLinkedNode<E>* addToHead(E data); // O(1)
SinglyLinkedNode<E>* addToTail(E data); // O(n)
SinglyLinkedNode<E>* getNodeAt(unsigned int i); // O(n)
SinglyLinkedNode<E>* getHeadNode(); // O(1)
SinglyLinkedNode<E>* getTailNode(); // O(1)
bool contains(SinglyLinkedNode<E>* singlyLinkedNode); // O(n)
E getDataAt(unsigned int i); // O(n)
E getHeadData(); // O(1)
E getTailData(); // O(1)
bool contains(E data); // O(n)
E remove(E data); // O(n)
E removeAt(unsigned int i); // O(n)
E removeHead(); // O(1)
E removeTail(); // O(size)
void clear(); // O(size)
bool isEmpty(); // O(1)
unsigned int getSize(); // O(1)
~SinglyLinkedList();
};
template <class E>
SinglyLinkedList<E>::SinglyLinkedList() {
head = nullptr;
tail = nullptr;
size = 0;
}
template <class E>
SinglyLinkedList<E>::SinglyLinkedList(const SinglyLinkedList<E>& singlyLinkedList) {
head = nullptr;
tail = nullptr;
size = 0;
SinglyLinkedNode<E>* currentNode = singlyLinkedList.head;
while (currentNode != nullptr) {
addToTail(currentNode->data);
currentNode = currentNode->nextNode;
}
}
template <class E>
void SinglyLinkedList<E>::operator = (const SinglyLinkedList<E> singlyLinkedList) {
head = nullptr;
tail = nullptr;
size = 0;
SinglyLinkedNode<E>* currentNode = singlyLinkedList.head;
while (currentNode != nullptr) {
addToTail(currentNode->data);
currentNode = currentNode->nextNode;
}
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::add(E data) {
return addToTail(data);
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::addAt(unsigned int i, E data) {
if (i > size)
return nullptr;
SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data);
if (size == 0) {
head = singlyLinkedNode;
tail = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
if (i == 0) {
singlyLinkedNode->nextNode = head;
head = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
SinglyLinkedNode<E>* currentNode = head;
for (unsigned int j = 1; j < i; j++)
currentNode = currentNode->nextNode;
singlyLinkedNode->nextNode = currentNode->nextNode;
currentNode->nextNode = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::addToHead(E data) {
SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data);
if (size == 0) {
head = singlyLinkedNode;
tail = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
singlyLinkedNode->nextNode = head;
head = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::addToTail(E data) {
SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data);
if (size == 0) {
head = singlyLinkedNode;
tail = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
tail->nextNode = new SinglyLinkedNode<E>(data);
tail = tail->nextNode;
size++;
return singlyLinkedNode;
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::getNodeAt(unsigned int i) {
if (size == 0 || i >= size)
return nullptr;
SinglyLinkedNode<E>* currentNode = head;
for (unsigned int j = 0; j < i; j++)
currentNode = currentNode->nextNode;
return currentNode;
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::getHeadNode() {
return head;
}
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::getTailNode() {
return tail;
}
template <class E>
bool SinglyLinkedList<E>::contains(SinglyLinkedNode<E>* singlyLinkedNode) {
SinglyLinkedList<E>* currentNode = head;
while (currentNode != nullptr)
if (currentNode == singlyLinkedNode)
return true;
return false;
}
template <class E>
E SinglyLinkedList<E>::getDataAt(unsigned int i) {
SinglyLinkedNode<E>* singlyLinkedNode = getNodeAt(i);
if (singlyLinkedNode == nullptr)
throw 0;
return singlyLinkedNode->data;
}
template <class E>
E SinglyLinkedList<E>::getHeadData() {
if (head == nullptr)
throw 1;
return head->data;
}
template <class E>
E SinglyLinkedList<E>::getTailData() {
if (tail == nullptr)
throw 2;
return tail->data;
}
template <class E>
bool SinglyLinkedList<E>::contains(E data) {
if (size == 0)
return false;
SinglyLinkedNode<E>* currentNode = head;
while (currentNode != nullptr) {
if (currentNode->data == data)
return true;
currentNode = currentNode->nextNode;
}
return false;
}
template <class E>
E SinglyLinkedList<E>::remove(E data) {
if (size == 0)
throw 3;
if (head->data == data)
return removeHead();
if (size > 1) {
SinglyLinkedNode<E>* currentNode = head;
while (currentNode->nextNode != nullptr) {
if (currentNode->nextNode->data == data) {
E data = currentNode->nextNode->data;
SinglyLinkedNode<E>* nodeToDelete = currentNode->nextNode;
if (nodeToDelete == tail)
tail = currentNode;
currentNode->nextNode = currentNode->nextNode->nextNode;
delete(nodeToDelete);
size--;
return data;
}
currentNode = currentNode->nextNode;
}
}
throw 4;
}
template <class E>
E SinglyLinkedList<E>::removeAt(unsigned int i) {
if (size == 0 || i >= size)
throw 5;
if (i == 0)
return removeHead();
if (i == (size - 1))
return removeTail();
SinglyLinkedNode<E>* currentNode = head;
for (unsigned int j = 1; j < i; j++)
currentNode = currentNode->nextNode;
E data = currentNode->nextNode->data;
SinglyLinkedNode<E>* nodeToDelete = currentNode->nextNode;
currentNode->nextNode = currentNode->nextNode->nextNode;
delete(nodeToDelete);
size--;
return data;
}
template <class E>
E SinglyLinkedList<E>::removeHead() {
if (size == 0)
throw 6;
if (size == 1) {
E data = head->data;
delete(head);
size--;
head = nullptr;
tail = nullptr;
return data;
}
if (size == 2) {
E data = head->data;
SinglyLinkedNode<E>* newHead = head->nextNode;
delete(head);
head = newHead;
tail = newHead;
size--;
return data;
}
SinglyLinkedNode<E>* newHead = head->nextNode;
E data = head->data;
delete head;
head = newHead;
size--;
return data;
}
template <class E>
E SinglyLinkedList<E>::removeTail() {
if (size == 0)
throw 7;
if (size == 1)
return removeHead();
if (size == 2) {
E data = tail->data;
delete(tail);
tail = head;
size--;
return data;
}
SinglyLinkedNode<E>* currentNode = head;
while (currentNode->nextNode->nextNode != nullptr)
currentNode = currentNode->nextNode;
E data = tail->data;
delete(tail);
currentNode->nextNode = nullptr;
tail = currentNode;
size--;
return data;
}
template <class E>
void SinglyLinkedList<E>::clear() {
while (size > 0)
removeHead();
}
template <class E>
bool SinglyLinkedList<E>::isEmpty() {
if (size == 0)
return true;
}
template <class E>
unsigned int SinglyLinkedList<E>::getSize() {
return size;
}
template <class E>
SinglyLinkedList<E>::~SinglyLinkedList() {
clear();
}
The memory leak only asserts when I have more than one node in the list. I tried going step by step using the debugger, but everything seems to be working fine. Any leads would be very helpful.
At least in this function
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::addToTail(E data) {
SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data);
if (size == 0) {
head = singlyLinkedNode;
tail = singlyLinkedNode;
size++;
return singlyLinkedNode;
}
tail->nextNode = new SinglyLinkedNode<E>(data);
tail = tail->nextNode;
size++;
return singlyLinkedNode;
}
called by the function add
template <class E>
SinglyLinkedNode<E>* SinglyLinkedList<E>::add(E data) {
return addToTail(data);
}
there is a memory leak.
A new node is allocated twice when the list is not empty
SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data);
and
tail->nextNode = new SinglyLinkedNode<E>(data);
And the allocated node pointed to by the pointer singlyLinkedNode is not deleted.
There is other problematic code in your program. For example the parameter of the assignment operator
void operator = (const SinglyLinkedList<E> singlyLinkedList);
should be a reference. Otherwise the operator will be inefficient because it will create a new temporary list.
And moreover it also produces numerous memory leaks because it does not clear the current list.
template <class E>
void SinglyLinkedList<E>::operator = (const SinglyLinkedList<E> singlyLinkedList) {
head = nullptr;
tail = nullptr;
size = 0;
SinglyLinkedNode<E>* currentNode = singlyLinkedList.head;
while (currentNode != nullptr) {
addToTail(currentNode->data);
currentNode = currentNode->nextNode;
}
}
You need to revise your entire program.:)
I am trying to figure out what is wrong with my cpp code, and i need your help!
valgrind Output:
the error occurs here (in the test file):
list = list.apply(getLen);
the function getLen:
string getLen(string str)
{
return std::to_string(str.length());
}
the generic function apply:
template<class T>
template<class Operation>
SortedList<T> SortedList<T>::apply(Operation operation) const{//TODO: 6 blocks are indirectly lost.
Node<T>* current_node_to_check = head;
SortedList<T> new_sorted_list;
for (int i = 0; i < list_length; ++i) {
T result = operation(current_node_to_check->info);
new_sorted_list.insert(result);
current_node_to_check = current_node_to_check->next;
}
return new_sorted_list;
}
the Node struct implementation:
template<class T>
struct Node{
T info;
Node<T>* next;
explicit Node(const T& new_info) : info(new_info), next(nullptr){}
};
the test file:
#include <iostream>
#include "SortedList.h"
#include "examDetails.h"
using std::cout;
using std::endl;
using std::string;
using namespace mtm;
#define TEST(num) cout << endl << "TEST " << (num) << endl;
string getLen(string str)
{
return std::to_string(str.length());
}
bool isTrollLink(const ExamDetails& exam) {
return (exam.getLink().find("tinyurl") != string::npos);
}
template<class T>
void printList(SortedList<T> list) {
for (auto it = list.begin(); !(it == list.end()); ++it) {
cout << *it << endl;
}
cout << endl;
}
int main()
{
.
.
.
TEST("1.5")
SortedList<string> lst1 = SortedList<string>();
lst1.insert("Charlie");
lst1.insert("Bob");
lst1.insert("Alice");
lst1.insert("Donald");
printList(lst1);
TEST("1.6")
SortedList<ExamDetails> lst2;
lst2.insert(exam1);
lst2.insert(exam2);
printList(lst2);
TEST("1.7")
SortedList<string> lst3 = lst1;
printList(lst3);
TEST("1.8")//TODO: 6 blocks are indirectly lost.
lst3 = lst3.apply(getLen);
printList(lst3);
TEST("1.9")
lst3.remove(lst3.begin());
printList(lst3);
TEST("1.10")
SortedList<ExamDetails> lst4 = lst2.filter(isTrollLink);
printList(lst2);
cout << "----------" << endl;
printList(lst4);
return 0;
}
the generic class file:
#ifndef NEW_SORTED_LIST_SORTEDLIST_H
#define NEW_SORTED_LIST_SORTEDLIST_H
#include <stdexcept>
using std::cout;
using std::endl;
namespace mtm {
template<class T>
struct Node{
T info;
Node<T>* next;
explicit Node(const T& new_info) : info(new_info), next(nullptr){}
};
template<class T>
class SortedList {
private:
Node<T>* head;
int list_length;
static const int empty = 0;
void deleteNodes();
public:
class const_iterator;
SortedList();
~SortedList();
SortedList(const SortedList &to_copy);
SortedList& operator=(const SortedList &to_assign);
void insert(const T &to_insert);
void remove(const const_iterator& iterator);
int length() const;
template<class Condition>
SortedList filter(Condition condition) const;
template<class Operation>
SortedList apply(Operation operation) const;
const_iterator begin() const;
const_iterator end() const;
};
template<class T>
class SortedList<T>::const_iterator{
const SortedList<T>* sortedListPointer;
int index;
const_iterator(const SortedList<T>* sortedListPointer, int index) : sortedListPointer(sortedListPointer),
index(index){}
friend class SortedList<T>;
static const int first = 1;
public:
const_iterator(const const_iterator&) = default;
const_iterator& operator=(const const_iterator&) = default;
const T& operator*(){
if (index > sortedListPointer->length()+1 || index<0){
throw std::out_of_range("error: iterator out of range");//TODO
}
Node<T>* current = sortedListPointer->head;
for (int i = 1; i < index; ++i) {
current = current->next;
}
return current->info;
}
const_iterator& operator++() {
++index;
if (index > sortedListPointer->length()+1){
throw std::out_of_range("error: iterator out of range");//TODO
}
return *this;
}
const_iterator operator++(int){
SortedList<T>::const_iterator result = *this;
++*this;
return result;
}
bool operator==(const const_iterator& it) const{
return (index == it.index);
}
};
template<class T>
typename SortedList<T>::const_iterator SortedList<T>::begin() const{
return const_iterator(this, const_iterator::first);
}
template<class T>
typename SortedList<T>::const_iterator SortedList<T>::end() const{
return const_iterator(this, this->length()+1);
}
template<class T>
SortedList<T>::SortedList() : head(nullptr), list_length(empty){}
template<class T>
SortedList<T>::~SortedList() {
deleteNodes();
}
template<class T>
SortedList<T>::SortedList(const SortedList& to_copy){
Node<T>* current_to_copy = to_copy.head;
Node<T>* current = nullptr;
Node<T>* new_head;
if (to_copy.list_length == 0){
return;
}else{
Node<T>* new_node = new Node<T>(current_to_copy->info);
//exception
//new_node->info = current_to_copy->info;
//new_node->next = nullptr;
current = new_node;
current_to_copy = current_to_copy->next;
new_head = current;
}
while (current_to_copy){
Node<T>* new_node = new Node<T>(current_to_copy->info);
//exception
//new_node->info = current_to_copy->info;
//new_node->next = nullptr;
current->next = new_node;
current = current->next;
current_to_copy = current_to_copy->next;
}
list_length = to_copy.list_length;
head = new_head;
}
template<class T>
void SortedList<T>::deleteNodes(){
if (list_length == empty){
head = nullptr;
return;
}
Node<T>* current = head->next;
for (int i = 1; i < list_length; ++i) {
Node<T>* previous = head;
Node<T>* temp = current->next;
delete current;
current = temp;
previous->next = current;
}
delete head;
head = nullptr;
list_length = empty;
}
template<class T>
SortedList<T>& SortedList<T>::operator=(const SortedList &to_assign){
if (this == &to_assign){
return *this;
}
head = nullptr;
Node<T>* current_to_assign = to_assign.head;
Node<T>* current;
Node<T>* new_head;
if (current_to_assign){
Node<T>* first_node = new Node<T>(current_to_assign->info);
current = first_node;
current_to_assign = current_to_assign->next;
new_head = first_node;
}else{
deleteNodes();
head = nullptr;
return *this;
}
while (current_to_assign){
Node<T>* new_node = new Node<T>(current_to_assign->info);
current->next = new_node;
current = current->next;
current_to_assign = current_to_assign->next;
}
head = new_head;
list_length = to_assign.list_length;
return *this;
}
template<class T>
void SortedList<T>::insert(const T &to_insert){
Node<T>* new_node = new Node<T>(to_insert);
Node<T>* current = head;
if (!current){
head = new_node;
list_length++;
return;
}
Node<T>* previous = head;
if (current->info < to_insert){
current = current->next;
}else{
new_node->next = current;
head = new_node;
list_length++;
return;
}
while (current){
if (current->info < to_insert){
current = current->next;
previous = previous->next;
}else{
new_node->next = current;
previous->next = new_node;
list_length++;
return;
}
}
previous->next = new_node;
list_length++;
}
template<class T>
void SortedList<T>::remove(const SortedList<T>::const_iterator& iterator){
if (list_length == 1){
list_length--;
delete head;
}
int index = iterator.index;
if (index == 1){
Node<T>* temp = head->next;
delete head;
head = temp;
list_length--;
return;
}
Node<T>* current = head;
Node<T>* previous = nullptr;
for (int i = 1; i < index-1; ++i) {
if ((i+1) == index-1){
previous = current;
}
current = current->next;
}
previous->next = current->next;
delete current;//TODO destructor(?)
list_length--;
}
template<class T>
int SortedList<T>::length() const{
return list_length;
}
template<class T>
template<class Condition>
SortedList<T> SortedList<T>::filter(Condition condition) const{
Node<T>* current_node_to_check = head;
SortedList<T> new_sorted_list;
for (int i = 0; i < list_length; ++i) {
if (condition(current_node_to_check->info)){
new_sorted_list.insert(current_node_to_check->info);
}
current_node_to_check = current_node_to_check->next;
}
return new_sorted_list;
}
template<class T>
template<class Operation>
SortedList<T> SortedList<T>::apply(Operation operation) const{//TODO: 6 blocks are indirectly lost.
Node<T>* current_node_to_check = head;
SortedList<T> new_sorted_list;
for (int i = 0; i < list_length; ++i) {
T result = operation(current_node_to_check->info);
new_sorted_list.insert(result);
current_node_to_check = current_node_to_check->next;
}
return new_sorted_list;
}
}
#endif //NEW_SORTED_LIST_SORTEDLIST_H
without the test 1.8, the code works great with no errors at all!
What should I do to fix it?
thanks
You allocated a SortedList<string> object in main() which allocated memory and never freed it.
The other blocks belong to the std::string objects inside the list. They are only lost because the list holding them lost track of them.
When doing your analysis, don't worry about the 6 indirectly lost blocks, focus on the one directly lost one.
Almost certainly this is a violation of the "Rule of Five". Your SortedList does an allocation in its constructor and doesn't properly manage that allocation in its move-assignment operator.
Looking at your code in the copy assignment operator, this line is causing the leak
head = nullptr;
It shouldn't be needed, you later call deleteNodes() which will do that anyway, and by erasing head beforehand you prevent deleteNodes() from doing its work.
So I am attempting to create a Linked List that can store books for a imaginative library. Within the linked list, each node should contain the branch of library, the author's name, the book's title, and the number of copies of said book.
I'm having difficulty creating a linked list with multiple fields per node. How would I go about it so that each node can store 3 separate strings and an integer, and then finally, a pointer to the next node?
Here is my current code.
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <stdexcept>
using namespace std;
template<typename T>
class Node
{
public:
T element;
Node<T>* next;
Node()
{
next = nullptr;
}
Node(T element) // Constructor
{
this->element = element;
next = nullptr;
}
};
template<typename T>
class Iterator : public std::iterator<std::forward_iterator_tag, T>
{
public:
Iterator(Node<T>* p)
{
current = p;
}
Iterator operator++() // Prefix ++
{
current = current->next;
return *this;
}
Iterator operator++(int dummy) // Postfix ++
{
Iterator temp(current);
current = current->next;
return temp;
}
T& operator*()
{
return current->element;
}
bool operator==(const Iterator<T>& iterator)
{
return current == iterator.current;
}
bool operator!=(const Iterator<T>& iterator)
{
return current != iterator.current;
}
private:
Node<T>* current;
};
template<typename T>
class LinkedList
{
public:
LinkedList();
LinkedList(const LinkedList<T>& list);
virtual ~LinkedList();
void addFirst(T element);
void addLast(T element);
T getFirst() const;
T getLast() const;
T removeFirst() throw (runtime_error);
T removeLast();
void add(T element);
void add(int index, T element);
void clear();
bool contains(T element) const;
T get(int index) const;
int indexOf(T element) const;
bool isEmpty() const;
int lastIndexOf(T element) const;
void remove(T element);
int getSize() const;
T removeAt(int index);
T set(int index, T element);
Iterator<T> begin() const
{
return Iterator<T>(head);
}
Iterator<T> end() const
{
return Iterator<T>(tail->next);
}
private:
Node<T>* head;
Node<T>* tail;
int size;
};
template<typename T>
LinkedList<T>::LinkedList()
{
head = tail = nullptr;
size = 0;
}
template<typename T>
LinkedList<T>::LinkedList(const LinkedList<T>& list)
{
head = tail = nullptr;
size = 0;
Node<T>* current = list.head;
while (current != nullptr)
{
this->add(current->element);
current = current->next;
}
}
template<typename T>
LinkedList<T>::~LinkedList()
{
clear();
}
template<typename T>
void LinkedList<T>::addFirst(T element)
{
Node<T>* newNode = new Node<T>(element);
newNode->next = head;
head = newNode;
size++;
if (tail == nullptr)
tail = head;
}
template<typename T>
void LinkedList<T>::addLast(T element)
{
if (tail == nullptr)
{
head = tail = new Node<T>(element);
}
else
{
tail->next = new Node<T>(element);
tail = tail->next;
}
size++;
}
template<typename T>
T LinkedList<T>::getFirst() const
{
if (size == 0)
throw runtime_error("Index out of range");
else
return head->element;
}
template<typename T>
T LinkedList<T>::getLast() const
{
if (size == 0)
throw runtime_error("Index out of range");
else
return tail->element;
}
template<typename T>
T LinkedList<T>::removeFirst() throw (runtime_error)
{
if (size == 0)
throw runtime_error("No elements in the list");
else
{
Node<T>* temp = head;
head = head->next;
if (head == nullptr) tail = nullptr;
size--;
T element = temp->element;
delete temp;
return element;
}
}
template<typename T>
T LinkedList<T>::removeLast()
{
if (size == 0)
throw runtime_error("No elements in the list");
else if (size == 1)
{
Node<T>* temp = head;
head = tail = nullptr;
size = 0;
T element = temp->element;
delete temp;
return element;
}
else
{
Node<T>* current = head;
for (int i = 0; i < size - 2; i++)
current = current->next;
Node<T>* temp = tail;
tail = current;
tail->next = nullptr;
size--;
T element = temp->element;
delete temp;
return element;
}
}
template<typename T>
void LinkedList<T>::add(T element)
{
addLast(element);
}
template<typename T>
void LinkedList<T>::add(int index, T element)
{
if (index == 0)
addFirst(element);
else if (index >= size)
addLast(element);
else
{
Node<T>* current = head;
for (int i = 1; i < index; i++)
current = current->next;
Node<T>* temp = current->next;
current->next = new Node<T>(element);
(current->next)->next = temp;
size++;
}
}
template<typename T>
void LinkedList<T>::clear()
{
while (head != nullptr)
{
Node<T>* temp = head;
head = head->next;
delete temp;
}
tail = nullptr;
size = 0;
}
template<typename T>
T LinkedList<T>::get(int index) const
{
if (index < 0 || index > size - 1)
throw runtime_error("Index out of range");
Node<T>* current = head;
for (int i = 0; i < index; i++)
current = current->next;
return current->element;
}
template<typename T>
int LinkedList<T>::indexOf(T element) const
{
// Implement it in this exercise
Node<T>* current = head;
for (int i = 0; i < size; i++)
{
if (current->element == element)
return i;
current = current->next;
}
return -1;
}
template<typename T>
bool LinkedList<T>::isEmpty() const
{
return head == nullptr;
}
template<typename T>
int LinkedList<T>::getSize() const
{
return size;
}
template<typename T>
T LinkedList<T>::removeAt(int index)
{
if (index < 0 || index >= size)
throw runtime_error("Index out of range");
else if (index == 0)
return removeFirst();
else if (index == size - 1)
return removeLast();
else
{
Node<T>* previous = head;
for (int i = 1; i < index; i++)
{
previous = previous->next;
}
Node<T>* current = previous->next;
previous->next = current->next;
size--;
T element = current->element;
delete current;
return element;
}
}
// The functions remove(T element), lastIndexOf(T element),
// contains(T element), and set(int index, T element) are
// left as an exercise
#endif
Given a struct, such as
struct Book
{
std::string branch;
std::string author;
std::string title;
int copies;
};
A LinkedList<Book> would have all the data elements you want in each Node.
I am having trouble implementing this with the class I have. So far as a linkedlist of type int or string it works great, but I am not sure how to navigate the list if I initialize it like
linkedlist<linkedlist<int>> nums;
From my program it seems that the head of each secondary list would be an entry in the primary, but my question is how would I navigate it?. For example how would I print all the values of each linkedlist, I am sure I am making this more difficult than it it, but any help would be appreciated.
/* Node Class */
template <typename T>
class Node {
public:
T data;
Node* next;
Node* previous;
Node(T data);
Node();
T getData();
};
template <typename T>
Node<T>::Node() {
this->next = NULL;
this->previous = NULL;
}
template <typename T>
Node<T>::Node(T data) {
this->data = data;
}
template <typename T>
T Node<T>::getData() {
return this->data;
}
/* Linked List: */
template <typename T>
class linkedlist {
private:
Node<T>* head;
Node<T>* tail;
int list_size;
public:
linkedlist();
T getHead();
T getTail();
int size();
void addnodetail(T);
void addnodehead(T);
void push(T);
T pop();
//T* peek();
bool isEmpty() const {
return head == NULL;
}
//T* get(int index);
void printlist();
void printListBackwards();
~linkedlist();
};
template <typename T>
linkedlist<T>::linkedlist() {
this->head = NULL;
this->tail = NULL;
this->list_size = 0;
}
template <typename T>
T linkedlist<T>::getHead() {
return this->head->data;
}
template <typename T>
T linkedlist<T>::getTail() {
return this->tail->data;
}
template <class T>
int linkedlist<T>::size() {
return this->list_size;
}
template <typename T>
void linkedlist<T>::addnodetail(T input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->tail->next = newnode;
newnode->previous = this->tail;
this->tail = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::addnodehead(T input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->head->previous = newnode;
newnode->next = this->head;
this->head = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::push(T input) {
this->addnodehead(input);
}
template <typename T>
T linkedlist<T>::pop() {
Node<T>* temp = this->head;
// T* temp = this->head;
this->head = this->head->next;
this->head->previous = NULL;
this->list_size = this->list_size - 1;
return temp->data;
}
/*
template <class T>
T* MyList<T>::peek() {
return this->head;
}
template <class T>
T* MyList<T>::get(int index) {
if (index == 0) {
return this->head;
} else if (index == this->list_size - 1) {
return this->tail;
} else if (index < 0 || index >= this->list_size) {
return NULL;
}
if (index < this->list_size / 2) {
T* temp = this->head;
int i = 0;
while (temp) {
if (i == index) { return temp; }
i++;
temp = temp->next;
}
} else {
T* temp = this->tail;
int i = this->list_size - 1;
while (temp) {
if (i == index) { return temp; }
i--;
temp = temp->previous;
}
}
return NULL;
}*/
template <typename T>
void linkedlist<T>::printlist() {
cout << "HEAD: ";
Node<T>* temp = this->head;
while(temp) {
cout << temp->data << " -> ";
temp = temp->next;
}
cout << "\b\b\b\b :TAIL" << endl;
}
template <class T>
void linkedlist<T>::printListBackwards() {
cout << "TAIL: ";
Node<T>* temp = this->tail;
while(temp) {
cout << temp->data << " -> ";
temp = temp->previous;
}
cout << "\b\b\b\b :HEAD" << endl;
}
template <typename T>
linkedlist<T>::~linkedlist() {
for(Node<T>* p;!isEmpty();){
p = head->next;
delete head;
head = p;
}
}
EDIT with copy constructor
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <iostream>
#include <ctype.h>
using namespace std;
using namespace std;
/*struct AdjListNode
{
int dest;
struct AdjListNode* next;
};
// A structure to represent an adjacency list
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
};
// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest)
{
struct AdjListNode* newNode =
(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->next = NULL;
return newNode;
}
// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
graph->V = V;
// Create an array of adjacency lists. Size of array will be V
graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));
// Initialize each adjacency list as empty by making head as NULL
int i;
for (i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest)
{
// Add an edge from src to dest. A new node is added to the adjacency
// list of src. The node is added at the begining
struct AdjListNode* newNode = newAdjListNode(dest);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
// Since graph is undirected, add an edge from dest to src also
newNode = newAdjListNode(src);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
// A utility function to print the adjacenncy list representation of graph
void printGraph(struct Graph* graph)
{
int v;
for (v = 0; v < graph->V; ++v)
{
struct AdjListNode* pCrawl = graph->array[v].head;
printf("\n Adjacency list of vertex %d\n head ", v);
while (pCrawl)
{
printf("-> %d", pCrawl->dest);
pCrawl = pCrawl->next;
}
printf("\n");
}
}
*/
/* Node Class */
template <typename T>
class Node {
public:
T data;
Node* next;
Node* previous;
Node(T data);
Node();
T getData();
};
template <typename T>
Node<T>::Node() {
this->next = NULL;
this->previous = NULL;
}
template <typename T>
Node<T>::Node(T data) {
this->data = data;
this->next = NULL;
}
template <typename T>
T Node<T>::getData() {
return this->data;
}
/* Linked List: */
template <typename T>
class linkedlist {
private:
Node<T>* head;
Node<T>* tail;
int list_size;
public:
linkedlist();
linkedlist(linkedlist& object);
T getHead();
T getTail();
int size();
void addtail(const T& input);
void addhead(const T& input);
void push(T);
T pop();
//T* peek();
bool isEmpty() const {
return head == NULL;
}
//T* get(int index);
void printlist();
void printListBackwards();
~linkedlist();
};
template <typename T>
linkedlist<T>::linkedlist() {
this->head = NULL;
this->tail = NULL;
this->list_size = 0;
}
template <typename T>
linkedlist<T>::linkedlist(linkedlist &object){
if(object.head == NULL){
head == NULL;
}
else {
head = new Node<T>(object.head->data);
Node<T>* temp = head;
Node<T>* objecthead = object.head;
Node<T>* current = objecthead;
while(current->next != NULL){
temp->next = new Node<T>(current->next->data);
current = current->next;
temp = temp->next;
}
}
}
template <typename T>
T linkedlist<T>::getHead() {
return this->head->data;
}
template <typename T>
T linkedlist<T>::getTail() {
return this->tail->data;
}
template <class T>
int linkedlist<T>::size() {
return this->list_size;
}
template <typename T>
void linkedlist<T>::addtail(const T& input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->tail->next = newnode;
newnode->previous = this->tail;
this->tail = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::addhead(const T& input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->head->previous = newnode;
newnode->next = this->head;
this->head = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::push(T input) {
this->addhead(input);
}
template <typename T>
T linkedlist<T>::pop() {
Node<T>* temp = this->head;
if(temp != NULL){
this->head = this->head->next;
this->head->previous = NULL;
this->list_size = this->list_size - 1;
return temp->data;
}
else{
cout << "Error:Empty List!";
exit (EXIT_FAILURE);
}
}
/*
template <class T>
T* MyList<T>::peek() {
return this->head;
}
template <class T>
T* MyList<T>::get(int index) {
if (index == 0) {
return this->head;
} else if (index == this->list_size - 1) {
return this->tail;
} else if (index < 0 || index >= this->list_size) {
return NULL;
}
if (index < this->list_size / 2) {
T* temp = this->head;
int i = 0;
while (temp) {
if (i == index) { return temp; }
i++;
temp = temp->next;
}
} else {
T* temp = this->tail;
int i = this->list_size - 1;
while (temp) {
if (i == index) { return temp; }
i--;
temp = temp->previous;
}
}
return NULL;
}*/
template <typename T>
void linkedlist<T>::printlist() {
cout << "STACK" << endl;
cout << "-------------------" << endl;
Node<T>* temp = this->head;
while(temp) {
cout << "\t" << temp->data << endl;
temp = temp->next;
}
//cout << "\b\b\b\b :TAIL" << endl;
}
template <class T>
void linkedlist<T>::printListBackwards() {
cout << "TAIL: ";
Node<T>* temp = this->tail;
while(temp) {
cout << temp->data << " -> ";
temp = temp->previous;
}
cout << "\b\b\b\b :HEAD" << endl;
}
template <typename T>
linkedlist<T>::~linkedlist() {
for(Node<T>* p;!isEmpty();){
p = head->next;
delete head;
head = p;
}
}
#endif // LINKEDLIST_H
I've gone through a bunch of threads trying to understand what is going on exactly with linked lists and bubblesort, and I think I get the bulk of it.
Right now my program is simply crashing when I get to the sort function and I am not sure why. Hopefully another set of eyes will see what I do not.
Any help is greatly appreciated.
DoublyList.h:
#include "listNode.h"
#ifndef DOUBLYLIST_H
#define DOUBLYLIST_H
template <typename T>
class DoublyList
{
public:
DoublyList();
~DoublyList();
void addFront(T d);
void addBack(T d);
T removeFront();
T removeBack();
T peak();
bool isEmpty();
int getSize();
void printList();
void sortList();
private:
ListNode<T> *front;
ListNode<T> *back;
int numOfElements;
};
template <typename T>
DoublyList<T>::DoublyList(){
front = NULL;
back = NULL;
numOfElements = 0;
}
template <typename T>
DoublyList<T>::~DoublyList(){
if(numOfElements!=0){
ListNode<T> *current;
current = front;
while (current != back)
{
ListNode<T> *temp = current;
current = current->next;
temp->next = NULL;
temp->prev = NULL;
delete temp;
numOfElements--;
}
//at this point current = back, now delete it
current->next = NULL;
current->prev = NULL;
delete current;
numOfElements--;
}
//this is a safeguard if you create a LL and then delete it without doing anything to it
else{
cout<<"deleted empty LL"<<endl;
delete front;
delete back;
}
}
template <typename T>
void DoublyList<T>::addFront(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
back = node;
}
else{
front->prev = node;
}
node->next = front;
front = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeFront()
{
if (isEmpty()){
return T();
}
else
{
ListNode<T>* temp = front;
if (front->next == 0){
back = 0;
}
else
{
front->next->prev = 0;
}
front = front->next;
temp->next = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
void DoublyList<T>::addBack(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
front = node;
}
else{
back->next = node;
}
node->prev = back;
back = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeBack()
{
if (isEmpty()) {
return T();
}
else
{
ListNode<T>* temp;
temp = back;
if (back->prev == 0){
front = 0;
}
else{
back->prev->next = 0;
}
back = back->prev;
temp->prev = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
T DoublyList<T>::peak()
{
if (isEmpty()) {
return T();
}
return front->data;
}
template <typename T>
int DoublyList<T>::getSize(){
return numOfElements;
}
template <typename T>
bool DoublyList<T>::isEmpty(){
if(numOfElements == 0){
return true;
}
else{
return false;
}
}
template <typename T>
void DoublyList<T>::printList(){
if(numOfElements!=0){
ListNode<T> *current = front;
while(current!=back)
{
cout<<current->data<<endl;
current = current->next;
}
cout<<back->data<<endl;
}
else{
cout<<"list is empty"<<endl;
}
}
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current;
ListNode<T> *dummy;
ListNode<T> *next;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current -> next != NULL){
if(current-> data < current -> next -> data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy -> data = current -> data;
current -> data = current -> next -> data;
current -> next -> data = dummy -> data;
}
current = current -> next;
}
}
}
#endif
listNode.h:
#include <iostream>
#ifndef LISTNODE_H
#define LISTNODE_H
using namespace std;
template <typename T>
class ListNode
{
public:
T data;//the data that we will store
ListNode();
ListNode(int d);
~ListNode();
ListNode *next;//int and ptr and the member variables
ListNode *prev;
};
template <typename T>
ListNode<T>::ListNode(int d){
data = d;
next = NULL;
prev = NULL;
}
template <typename T>
ListNode<T>::ListNode(){}
template <typename T>
ListNode<T>::~ListNode(){
delete next;
delete prev;
cout<<"deleted Node"<<endl;
}
#endif
testList.cpp
#include <iostream>
#include "doublyList.h"
#include "genericQueue.h"
int main(){
DoublyList<int> testQueue;
testQueue.addBack(3);
testQueue.addBack(5);
testQueue.addBack(2);
testQueue.addBack(10);
testQueue.addBack(1);
cout << "Before Sort: " << endl;
testQueue.printList();
cout << "After Sort: " << endl;
testQueue.sortList();
testQueue.printList();
}
The erors I could find so far are:
Your default ListNode() constructor doesn't null the next and prev pointers.
In void DoublyList<T>::sortList() you don't initialize dummy, so it just points into nowhere. Actually there is no reason to use a node list at all, you can just directly use a variable of type T.
You don't initialize current in the same function and you actually should reset current to e.g. front at the beginning of each outer loop.
You don't use next at all (and don't need to), so just remove it.
To sum it up, this is what void DoublyList<T>::sortList() could look like:
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current=front;
T dummy;
if (current == NULL) return;
if (current->next == NULL) return;
int swapped = 1;
while (swapped){
current = front;
swapped = 0; //last pass unless there is a swap
while (current->next != NULL){
if (current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy = current->data;
current->data = current->next->data;
current->next->data = dummy;
}
current = current->next;
}
}
}
and this is my suggestion for the ListNode constructor.
template <typename T>
ListNode<T>::ListNode() :
next(nullptr),
prev(nullptr),
data{}
{}
Besides that, I also agree with DaveB that swapping pointers is the approach you should actually use.
To start with you need to initialize current in your sort function,
current = first;
template <typename T>
void DoublyList<T>::sortList(){
ListNode<T> *current;
ListNode<T> *next;
T tmp;
current = front;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current->next != nullptr){
if(current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
tmp = current->data;
current->data = current->next->data;
current->next->data = tmp;
}
current = current -> next;
}
if (swapped) // go back to start of list for next pass
current = front;
}
}