I've created a simple dynamic template list and i'm having some issue clearing the entire list.
List.h
#ifndef LIST_H
#define LIST_H
#include <Node.h>
template <class T> class List
{
public:
typedef Node<T> node_type;
typedef node_type* node_pointer;
typedef T data_type;
typedef T& reference_type;
List();
void push_back(data_type);
reference_type at(int);
void clear();
void swap(int,int);
int size();
private:
int list_size = 0;
node_pointer head, tail;
};
template <class T> List<T>::List()
{
head=NULL;
tail=NULL;
}
template <class T> void List<T>::push_back(data_type data)
{
if(head == NULL) {
head = new node_type(data);
tail = head;
} else {
node_pointer temp = new node_type(data);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
list_size++;
}
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
node_pointer pointer=head;
for(int i=0; i<x; i++)
pointer=pointer->getNext();
return pointer->getData();
}
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
for(int i=0; i<list_size; i++) {
node_pointer temp = pointer;
pointer=pointer->getNext();
delete(temp);
}
head=NULL;
list_size=0;
}
template <class T> void List<T>::swap(int x, int y)
{
data_type buffer=at(x);
at(x)=at(y);
at(y)=buffer;
}
template <class T> int List<T>::size()
{
return list_size;
}
#endif // LIST_H
Node.h
template <class T> class Node
{
public:
typedef T data_type;
typedef T& reference_type;
Node(data_type _data);
void setData(data_type);
void setNextNull();
void setNext(Node*);
reference_type getData();
Node* getNext();
private:
data_type data;
Node* next;
};
template <class T> Node<T>::Node(data_type _data) : data(_data)
{
setNextNull();
}
template <class T> void Node<T>::setData(data_type _data)
{
data=_data;
}
template <class T> void Node<T>::setNextNull()
{
next=NULL;
}
template <class T> void Node<T>::setNext(Node* _next)
{
next=_next;
}
template <class T> typename Node<T>::reference_type Node<T>::getData()
{
return data;
}
template <class T> typename Node<T>::Node* Node<T>::getNext()
{
return next;
}
If I clear the list calling the "clear" method I get all sorts of errors in almost every other method, but if I use the version below the list works perfectly.
template <class T> void List<T>::clear()
{
head=NULL;
tail=NULL;
list_size=0;
}
The problem only appears if I use the delete function to clear memory. How can I solve this issue?
Your code is very dangerious, because you skipped important checks. Try to use following implementation of at():
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
if (x < 0 || x >= list_size || list_size <= 0)
return DATA_WITH_ERROR_FLAG; // since you return data instead of pointer,
// you can't return NULL here
// (you need special constant for error status
// or support it another way)
node_pointer pointer=head;
for(int i=0; i<x; i++)
{
if (!pointer)
return DATA_WITH_ERROR_FLAG;
pointer=pointer->getNext();
}
if (!pointer)
return DATA_WITH_ERROR_FLAG;
return pointer->getData();
}
After it you have to add checks after each at() call. For example, you have to modify swap() to make it safe too:
template <class T> void List<T>::swap(int x, int y)
{
data_type v1=at(x);
data_type v2=at(y);
if (v1 == DATA_WITH_ERROR_FLAG || v2 == DATA_WITH_ERROR_FLAG)
return; // and somehow set error flag!
data_type t=v1;
v1 = v2;
v2 = t;
}
I.e. you need to check correctness everywhere if you don't like such problems. And it is necessary to support returninig of error status to simplify analysis of errors.
Change your clear() method to this:
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
while (pointer != NULL) {
node_pointer temp = pointer-getNext();
delete pointer;
pointer = temp;
}
head=NULL;
tail=NULL;
list_size=0;
}
You have a memory leak in your code. You don't delete all the list by simply pointing head and tail to NULL.
The best way to do this is to create a delete() function then loop through the whole list while it is not empty and delete node by node.
void deleteHead()
{
if(head != NULL)
{
node *temp = head;
head = head->next;
delete temp;
size--;
}
}
bool isEmpty()
{
return head==NULL;
//return size == 0; <-- this is ok as well.
}
void clear()
{
while(! isEmpty())
{
deleteHead();
}
tail = head; //head = NULL
}
Related
Where is the problem in my customLinkedList???
I have create that customLinkedList, that can contain all type of values.
I don't know where is the problem...
on the last line of the main appear the error "expression must have class type".
Someone can help me?
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
/*
struct ha tutte le variabili pubbliche
*/
//CLASS NODE
template <class T>
class Node {
public:
T data;
Node<T>*next;
Node();
Node(T v);
Node<T>(T v, Node *nextNode);
T getValue();
};
template <class T>
Node<T>::Node() {
data = null;
next = nullptr;
}
template <class T>
Node<T>::Node(T v) {
data = v;
next = NULL;
}
template <class T>
Node<T>::Node(T v, Node *nextNode) {
data = v;
next = nextNode;
}
template <class T>
T Node<T>::getValue() {
return data;
}
/*-------------------------------------------------------------------------------------------------*/
/*
class tutte le variabili private.
uso etichetta public: per avere variabili e funzioni pubbliche
*/
//CLASS LIST
template <class T>
class List {
Node<T> *head;
public:
List();
~List();
void addFirst(T v);
void deleteN(T v);
Node<T> *find(T v);
};
template <class T>
List<T>::List() {
head = NULL;
}
template <class T>
List<T>::~List() {
Node<T> *tmp = head;
while (tmp != NULL) {
tmp = head->next;
delete head;
head = tmp;
}
}
template <class T>
void List<T>::addFirst(T v) {
Node<T> *n = new Node<T>();
n->data = v;
n->next = head;
head = n;
}
template <class T>
Node<T>* List<T>::find(T v) {
Node<T> * tmp = head;
while (tmp->data != v && tmp != NULL) {
tmp = tmp->next;
}
return tmp;
}
template <class T>
void List<T>::deleteN(T v) {
Node<T> *iter = this->head;
Node<T> *temp = iter;
while (iter != NULL) {
if (iter->data == data) {
temp->next = iter->next;
delete iter;
break;
}
else {
temp = iter;
iter = iter->next;
}
}
return;
}
int main() {
Node<int> n1();
Node<int> n2(5);
Node<char> n3('z');
char c = n3.getValue();
printf("%c" , c);
// with Node all work well...
List<string> l1();
l1.addFirst("Hello");
}
I suspect that
List<string> l1();
should be
List<std::string> l1;
string may be defined somewhere and hence cause the error.
I get this error when I try to compile either popRight or popLeft. Why? Here are the codes.
Dequeue class
#include "node.h"
template <class T>
class Dequeue
{
public:
void pushLeft(T data);
void popLeft();
T left();
void pushRight(T data);
void popRight();
T right();
bool empty();
private:
int length;
};
template<typename T>
bool Dequeue<T>::empty()
{
if (length == 0)
{
return true;
}
else
return false;
}
template<typename T>
void Dequeue<T>::pushLeft(T data)
{
if (empty() == true)
{
left->setData(data);
right->setData(data);
}
else if (left->getData() == right->getData())
{
left->setData(data);
}
else
{
node<T> *aux = new node<T>;
aux->setData(data);
left->setPrevious(aux);
aux->setNext(left);
left = aux;
}
length++;
}
template<typename T>
void Dequeue<T>::pushRight(T data)
{
if (empty() == true)
{
right->setData(data);
left->setData(data);
}
else if (right->getData() == left->getData())
{
right->setData(data);
}
else
{
node<T> *aux = new node<T>;
aux->setData(data);
right->setPrevious(aux);
aux->setNext(right);
right = aux;
}
length++;
}
template<typename T>
void Dequeue<T>::popLeft()
{
node<T> *node = left->getNext();
node->setPrevious(NULL);
left = node;
}
template<typename T>
void Dequeue<T>::popRight()
{
node<T> *node = right->getPrevious();
node->setNext(NULL);
right = node;
}
Node Class
template <class T>
class node
{
public:
node(T data);
node(T data, node<T>* next);
T getData();
node<T>* getNext();
void setData(T data);
void setNext(node<T>* next);
void setPrevious(node<T>* previous);
private:
T data;
node<T> *next;
node<T> *previous;
node<T> *left;
node<T> *right;
};
template <typename T>
node<T>::node(T data)
{
this->data = data;
this->next = NULL;
this->previous = NULL;
}
template <typename T>
node<T>::node(T data, node<T>* next)
{
this->data = data;
this->next = next;
this->previous = previous;
}
template <typename T>
T node<T>::getData()
{
return this->data;
}
template <typename T>
node<T>* node<T>::getNext()
{
return this->next;
}
template <typename T>
void node<T>::setData(T data)
{
this->data=data;
}
template <typename T>
void node<T>::setNext(node<T>* next)
{
this->next = next;
}
template <typename T>
void node<T>::setPrevious(node<T>* previous)
{
this->previous = previous;
}
Ive been trying to solve this problem for like an hour but I just can't, can anyone help?
You declared left and right as functions. But it's clear from the way you use them in the rest of the code that they should be variables.
class Dequeue
{
public:
void pushLeft(T data);
void popLeft();
T left;
void pushRight(T data);
void popRight();
T right;
bool empty();
private:
int length;
};
I'm trying to implement a Queue using a linked list, but I get this error when I pass an integer to the enqueue function in main
Exception thrown: write access violation.
this->tail was nullptr.
here is my Queue.h
#include <iostream>
using namespace std;
template <class T >
class Node
{
public:
T data;
Node* next;
Node();
Node(T _data);
};
template <class T>
class Queue
{
public:
Node<T> *head, *tail;
int elemsCnt;
Queue();
~Queue();
int count();
void clear();
void enqueue(T);
T dequeue();
T front();
T back();
bool empty();
};
and this is my Queue.cpp which i wrote the functions ..
#include "Queue.h"
template <class T>
Node<T>::Node()
{
next = NULL;
}
template <class T>
Node<T>::Node(T _data)
{
data = _data;
next = NULL;
}
template <class T>
Queue<T>::Queue()
{
head = tail = NULL;
elemsCnt = 0;
}
template <class T>
Queue<T>::~Queue()
{
clear();
}
template <class T>
int Queue<T>::count()
{
return elemsCnt;
}
template <class T>
bool Queue<T>::empty()
{
return(elemsCnt == 0);
}
template <class T>
void Queue<T>::enqueue(T val)
{
Node<T>* inserted = new Node<T>(val);
tail->next = inserted;
tail = inserted;
++elemsCnt;
}
template <class T>
T Queue<T>::dequeue()
{
Node<T>* deleted = head;
T val = head->data;
head = head->next;
delete deleted;
--elemsCnt;
if (empty())
tail = NULL;
return val;
}
template <class T>
T Queue<T>::front()
{
return head->data;
}
template <class T>
T Queue<T>::back()
{
return tail->data;
}
template <class T>
void Queue<T>::clear()
{
while (!empty())
{
Node<T>* deleted = head;
head = head->next;
delete deleted;
--elemsCnt;
}
tail = NULL;
}
because initially your Queue is empty. when you have:
void Queue<T>::enqueue(T val)
{
Node<T>* inserted = new Node<T>(val);
tail->next = inserted; //at this point tail is still NULL
//it is illegal to try to access * and . on NULL
tail = inserted;
++elemsCnt;
}
if you want to fix it try this:
void Queue<T>::enqueue(T val)
{
Node<T>* inserted = new Node<T>(val);
if(this->elemsCnt==0)
{
//empty Queue
this->head=inserted;
this->tail=inserted;
}
else
{
//non empty
inserted->next=this->head; //make sure the new head can point to older head
this->head=inserted; update the pointer for head.
}
++elemsCnt;
}
just like the exception says, tail is NULL. Your enqueue method is not handling the case when the list is empty (head == tail == null).
template <class T>
void Queue<T>::enqueue(T val)
{
Node<T>* inserted = new Node<T>(val);
if (head == NULL)
{
head = tail = inserted;
}
else
{
tail->next = inserted;
tail = inserted;
}
++elemsCnt;
}
I've created this pretty simple dynamic list which is implemented with a template class:
Node.h
template <class T> class Node
{
public:
typedef T data_type;
typedef T& reference_type;
void setData(data_type);
void setNextNull();
void setNext(Node*);
reference_type getData();
Node* getNext();
private:
data_type data;
Node* next;
};
template <class T> void Node<T>::setData(data_type _data)
{
data=_data;
}
template <class T> void Node<T>::setNextNull()
{
next=NULL;
}
template <class T> void Node<T>::setNext(Node* _next)
{
next=_next;
}
template <class T> typename Node<T>::reference_type Node<T>::getData()
{
return data;
}
template <class T> typename Node<T>::Node* Node<T>::getNext()
{
return next;
}
List.h
#ifndef LIST_H
#define LIST_H
#include <Node.h>
template <class T> class List
{
public:
typedef Node<T> node_type;
typedef node_type* node_pointer;
typedef T data_type;
typedef T& reference_type;
List();
void push_back(data_type);
reference_type at(int);
void clear();
void swap(int,int);
int size();
private:
int list_size = 0;
node_pointer head, tail;
};
template <class T> List<T>::List()
{
head=NULL;
}
template <class T> void List<T>::push_back(data_type data)
{
if(head == NULL) {
head = new node_type;
head->setData(data);
tail = head;
} else {
node_pointer temp = new node_type;
temp->setData(data);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
list_size++;
}
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
node_pointer pointer=head;
for(int i=0; i<x; i++)
pointer=pointer->getNext();
return pointer->getData();
}
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
for(int i=0; i<list_size; i++) {
node_pointer temp = pointer;
pointer=pointer->getNext();
delete(temp);
}
head=NULL;
list_size=0;
}
template <class T> void List<T>::swap(int x, int y)
{
data_type buffer=at(x);
at(x)=at(y);
at(y)=buffer;
}
template <class T> int List<T>::size()
{
return list_size;
}
#endif // LIST_H
The list works perfectly with any form of data type, except when i use a class with a parameter inside it's constructor, then I get this error:
include/Node.h error: no matching function for call to ‘Player::Player()’
What am I doing wrong??
UPDATE 1
I've added a simple constructor as suggested but I get the same error
template <class T> Node<T>::Node(data_type _data)
{
data=_data;
}
You probably haven't defined a default constructor for your Player class. Just insert an empty constructor
Player() {}
And your problem will likely to be solved.
When you write a template method and use it in the main function like this:
Node<Player>
The compiler automatically calls the constructor of the Player class.
If you didn't define any constructors in Player, the compiler will use default constructor. However, any constructor you defined will hide the default one and force you to use this one.
For instance, a constructor like
Player(string, int, int)
Prevents you to create an object like this:
Player *p = new Player();
However, if you haven't written the constructor, the piece of code above would've worked just fine.
That's why your template needs a default constructor, iff you defined a parameterized constructor.
Your class Node should have a constructor which take a T so you can construct your T by copy instead of requiring to have a default constructor and copy.
your Node class would be something like:
template <class T>
class Node
{
public:
Node(const T& data) : data(data), next(0) {}
void setNextNull();
void setNext(Node*);
const T& getData() const { return data; }
T& getData() { return data; }
Node* getNext();
private:
T data;
Node* next;
};
and so you transform
head = new node_type;
head->setData(data);
by
head = new node_type(data);
I want to create a factory, that returns AVLNode, if BinaryTree is AVLTree, and Node if the tree is not AVL. I have following code:
#include "BinaryTree.h"
#include "AVLTree.h"
class NodeFactory {
public :
template <class T>
static Node<T>* getNode(BinaryTree<T>* tree);
};
template <class T>
Node<T>* NodeFactory::getNode(BinaryTree<T>* tree) {
if (tree->isAVL()) {
return new AVLNode<T>();
} else {
return new Node<T>();
}
}
UPD: (this is BinaryTree.h)
template <class T> class Node;
template <class T> class BinaryTree {
public:
BinaryTree() {
_isAVL = false;
root = new Node<T>();
}
bool isAVL() {
return _isAVL;
}
private:
T elem;
Node<T>* root;
bool _isAVL;
};
template <class T> class Node {
public:
Node() {
left = NULL;
right = NULL;
}
T get() {
return elem;
}
void setRight(const T elem) {
right = new Node<T>();
right->set(elem);
}
void setLeft(const T elem) {
left = new Node<T>();
left->set(elem);
}
private:
T elem;
Node* left;
Node* right;
};
I removed almost all methods to make code more readable.
Now i have this error during compilation: "expected initializer before '<' token". Also Qt do not highlights in Node, but highlights in BinaryTree
It's a syntax error. You need
template <class T> // or <typename T>
Node<T>* NodeFactory::getNode(BinaryTree<T>* tree) {