creating some old data structures in C++. Currently I am having an issue with a doubly-linked list class:
List.h:
template <class T>
class List{
private:
int size;
struct listNode{
T data;
listNode* next;
listNode* prev;
listNode(T newData);
};
listNode * head;
listNode * tail;
listNode * curr;
listNode * find(listNode * place, int k);
void removeCurrent(listNode * temp);
public:
List();
int getSize() const;
void insert(int loc, T data);
void remove(int loc);
T const & getItem(int loc) const;
void print();
};
List.cpp:
#include "List.h"
#include <iostream>
using namespace std;
template<class T>
List<T>::List(){
size = 0;
head->next = tail;
head->prev = NULL;
tail->prev = head;
tail->next = NULL;
}
// getSize: public method that returns the size of the list
template<class T>
int List<T>::getSize() const {
return size;
}
// insert: public method that inserts data into the list
template<class T>
void List<T>::insert(int loc, T data){
if(loc <1){
cout<<"Invalid Location"<<endl;
return;
}
curr = find(head,loc-1);
listNode * newNode = new listNode(data);
newNode->next = curr->next;
newNode->prev = curr;
newNode->next->prev = newNode;
curr->next = newNode;
size++;
}
// remove: public method that inserts data into the list
template<class T>
void List<T>::remove(int loc){
if(loc <1){
cout<<"Invalid Location"<<endl;
return;
}
curr = find(head,loc); // Find the node infront of the target
removeCurrent(curr); // Remove that node
}
// removeCurrent: helper function that removes the current node
template<class T>
void List<T>::removeCurrent(listNode* temp){
listNode* t = temp->next;
temp->data = t->data; // HACK: take data from next node
temp->next = t->next;
t->next->prev = temp;
delete t;
t=NULL;
size--;
}
// find: private helper function that returns a pointer to the k-1 node
template<class T>
listNode * List<T>::find(listNode * place, int k){
if((k==0) || (place==NULL))
return place;
else return find(place->next,k-1);
}
// getItem: returns data at location loc
template<class T>
T const& List<T>::getItem(int loc) const{
curr = find(head,loc);
return curr->data;
}
// print: prints the sequence of variables in the list
template<class T>
void List<T>::print()
{
curr = head;
while(curr->next != tail){
curr = curr->next;
cout<<curr->data<<endl;
}
}
//listNode constructor
template<class T>
List<T>::listNode::listNode(T newdata):data(newdata),next(NULL),prev(NULL)
{}
The error I'm getting is the following:
error: 'listNode' does not name a type.
I have tried different suggestions offered in similar troubleshooting posts, but I'm still getting this error. I have a main.cpp that includes List.cpp, but it's practically empty.
You're going to have to specify which listNode you're talking about at the find method's return type because you defined it as a member of the List class and you're also going to have to use typename (because List<T> is a dependent scope).
template <class T>
typename List<T>::listNode* List<T>::find(listNode* place, int k)
{
if ((k == 0) || (place == NULL))
return place;
else
return find(place->next, k-1);
}
Assuming you're using c++11, you may also want to use nullptr instead of NULL since its safer and use the initializer list at the List constructor.
Related
I read some of the other posts on this topic because there were quite a few, but they didn't really help my situation.
I am getting memory leaks in my implementation of a doubly linked list. I have to make my own so using list is not an option.
here are the two push functions I am using...
template <class T>
void dllist<T>::push_front(T val) {
node* new_node = new node;
new_node->value = val;
new_node->forward = head;
new_node->backward = nullptr;
if (head != nullptr)
head->backward = new_node;
head = new_node;
}
and...
template <class T>
void dllist<T>::push_back(T val) {
node* new_node = new node;
new_node->value = val;
new_node->forward = nullptr;
if (!head)
head = new_node;
else {
node* traveller = head;
while (traveller->forward != nullptr)
traveller = traveller->forward;
traveller->forward = new_node;
new_node->backward = traveller;
}
}
finally, here is my destructor
template <class T>
dllist<T>::~dllist() {
node* current = head;
while (current != nullptr) {
node* forward = current->forward;
delete current;
current = forward;
}
}
In main, I declare an object of type dllist called mylist and I make a few calls to push_front with some integer values and then push_back.
I am using the CRT library to check for leaks and there is a leak at each call to push_back or push_front.
I am confused because I thought I made my destructor correctly. Is there something else Im not seeing?
If anyone could point me in the right direction I'd appreciate it!
Thanks.
MRE
template<class T>
class dllist {
struct node {
T value;
node* forward;
node* backward;
};
node* head;
public:
dllist(); // default constructor
~dllist(); // default destructor
void push_front(T); // push element to the front of the list
void push_back(T); // push element to the back of the list
};
int main() {
{
dllist<int> mylist;
mylist.push_front(10);
mylist.push_front(12);
mylist.push_front(14);
mylist.push_front(16);
mylist.push_front(18);
mylist.push_front(19);
mylist.push_back(11);
mylist.push_back(21);
mylist.push_back(31);
mylist.push_back(41);
mylist.push_back(31);
mylist.push_back(41);
mylist.push_back(222);
}
_CrtDumpMemoryLeaks();
return 0;
}
template <class T>
dllist<T>::dllist() {
head = nullptr;
}
Whenever I implement the front() method (to return the first element of the doubly linked list) in the main I get a segmentation fault even though the back() method (returning the info of tail) that was implemented in a similar manner works. Can someone help?
template <class T>
class Node {
public:
T info;
Node<T>* next;
Node<T>* prev;
Node(const T info){
this->info = info;
next = NULL;
prev = NULL;
}
Node* getNode(T info){
Node* newnode = (Node *)malloc(sizeof(Node));
}
};
template <class T>
class DLlist {
private:
Node<T>* head;
Node<T>* tail;
int size;
public:
DLlist();
T front();
T back();
};
template<class T>
DLlist<T>::DLlist(){
head = NULL;
tail = NULL;
size = 0;
}
template <class T>
void DLlist<T>::addback(const T newdata){
if (isEmpty()){
Node<T> *newnode = new Node<T>(newdata);
head = tail = newnode;
size++;
return;
}
Node<T> *newnode;
newnode = new Node<T>(newdata);
newnode->prev = tail;
newnode->next = NULL;
tail->prev = newnode;
tail = newnode;
size++;
}
template <class T>
T DLlist<T>::front(){
return (head->info);
}
In your addback() function:
Node<T> *newnode; // Two lines where
newnode = new Node<T>(newdata); // one suffices
newnode->prev = tail;
newnode->next = NULL; // Unnecessary, your constructor did this
tail->prev = newnode; // THIS IS YOUR PROBLEM
tail = newnode;
size++;
Your tail should be setting its next pointer to the new node, not its previous. Drawing this stuff out on a piece of paper can go a long way in better understanding how it should work.
I am always willing to chalk up poor formatting on this site to copy/paste, but there are other things you can do to simplify your code, make it a bit more modern, etc.
So here's your code again, cleaned up a tad (This code went through clang-format using the Webkit style):
#include <iostream>
template <class T>
struct Node {
T info;
Node<T>* next = nullptr;
Node<T>* prev = nullptr;
Node(const T& info)
: info(info)
{
}
// Don't know why you need this, so just deleting it because it's a bad
// function
};
template <class T>
class DLlist {
private:
Node<T>* head = nullptr;
Node<T>* tail = nullptr;
int size = 0;
public:
DLlist() = default;
bool isEmpty() { return head == nullptr && tail == nullptr; }
void push_back(const T& newdata);
const T front() const;
const T back() const;
};
template <class T>
void DLlist<T>::push_back(const T& newdata)
{
if (isEmpty()) {
head = new Node<T>(newdata);
tail = head;
size++;
return;
}
Node<T>* newnode = new Node<T>(newdata);
newnode->prev = tail;
tail->next = newnode; // THIS WAS PROBABLY YOUR ISSUE
tail = newnode;
size++;
}
template <class T>
const T DLlist<T>::front() const
{
return head->info;
}
template <class T>
const T DLlist<T>::back() const
{
return tail->info;
}
int main()
{
DLlist<int> list;
list.push_back(42);
list.push_back(54);
std::cout << list.front() << '\n'; // 42 prints just fine, Debian w/ LLVM 9
}
So far, I have implemented a basic LinkedList. This works, but only for integers, and I would like it to work for any type.
I'm trying to get it to work for first any same type (i.e a LinkedList of just strings, or then just ints). After, I would like it to find a way of making it a LinkedList of anything (containing strings, then ints, then longs, all in one list).
#include <iostream>
struct Node{
Node(int value);
Node *next;
int data;
};
Node::Node(int value){
this->data = value;
this->next = nullptr;
}
struct LinkedList{
Node *head;
LinkedList();
void push_back(int value);
void print();
};
LinkedList::LinkedList(){
this->head = nullptr;
}
void LinkedList::push_back(int value){
Node *n = new Node(value);
if(this->head == nullptr){
this->head = n;
} else {
Node *cursor = this->head;
while (cursor->next != nullptr){
cursor = cursor->next;
}
cursor->next = n;
}
}
void LinkedList::print(){
Node *cursor = this->head;
while(cursor != nullptr){
std::cout << cursor->data << '\n';
cursor = cursor->next;
}
}
int main(){
LinkedList l = LinkedList();
l.push_back(1);
l.push_back(2);
l.print();
}
The above works, however, only for ints.
I'm knew, but I think the way is to use templates, however, doing so, I seem to be doing overkill? and it doesn't compile? Is there a cleaner was to do this?
#include <iostream>
template <typename T>
struct Node {
Node(T value);
int data;
Node<T> *next;
};
template <typename T>
Node<T>::Node(T value){
this->next = nullptr;
this->data = value;
}
template <typename T>
class LinkedList{
public:
LinkedList();
Node<T> *head;
void push_back(T data);
void print();
};
template <typename T>
LinkedList<T>::LinkedList(){
this->head = nullptr;
}
template <typename T>
void LinkedList<T>::push_back(T data){
Node *n = new Node(data);
if(this->head == nullptr){
this->head = n;
} else {
Node *cursor = this->head;
while(cursor->next != nullptr){
cursor = cursor->next;
}
cursor->next = n;
}
}
template <typename T>
void LinkedList<T>::print(){
Node *cursor = this->head;
while(cursor != nullptr){
std::cout << cursor->data << '\n';
cursor = cursor->next;
}
}
int main(){
LinkedList<T> *list = new LinkedList<T>();
list->push_back(1);
list->push_back(2);
list->push_back(3);
}
When declaring template classes, you use the "T" as a 'type placeholder' in the declaration and implementation (as you have done). However, when you want to actually use an object of the templated class, you replace the "T" with the actual type you want.
So, in your main (assuming you want an int type), you would have code like this:
int main(){
LinkedList<int> *list = new LinkedList<int>(); // THIS object uses "int" wherever "T" occurs in the declaration/implementation
list->push_back(1);
list->push_back(2);
list->push_back(3);
}
I also noticed a 'possible/probable error' in your struct declaration, where you specified that the data member is of (fixed) type int; maybe (almost certainly, actually, as you later assign a "T"-type value to it) you want this to vary according to the actual type requested? If so, make the following change:
template <typename T>
struct Node {
Node(T value);
// int data;
T data; // Data will be whatever "T" is when an object is created.
Node<T> *next;
};
Feel free to ask for further clarification and/or explanation.
so I am trying to make the queue with the linked list
which uses template in c++ to make any kind of data type queue.
However, it gives me a such error when I am trying to make template with "ListNode" class and its friend class "List":
Error C2955 'ListNode': use of class template requires template argument
this error is at line 33 where I declare head listnode and tail list node in List class
ListNode* list_head;
ListNode* list_tail;
How can I find solution to unite these two classes into template? please help.
below is my code sample:
template <typename T>
class ListNode
{
private:
T data;
int priority;
ListNode* prev;
ListNode* next;
public:
ListNode() { prev = next = NULL; }
ListNode(T d, int pr, ListNode* p, ListNode* n) { data = d; priority = pr; prev = p; next = n; }
template <typename T>
friend class List;
};
template <typename T>
class List
{
private:
ListNode* list_head;
ListNode* list_tail;
public:
List() { list_head = list_tail = NULL; }
~List() { clear(); }
bool isEmpty() { return list_head == NULL; }
bool contains(T value);
void addToQueList(T value, int priority);
T head() { return list_head->data; }
T tail() { return list_tail->data; }
T removeHead();
T removeTail();
void clear();
};
template <typename T>
bool List<T>::contains(T value)
{
ListNode *temp = list_head;
while (temp != NULL && temp->data != value)
temp = temp->next;
return temp != NULL;
}
I'm realitively new to using linked lists. I'm trying to overload the ostream opperator for a doubly linked list with decleration :
template <class T>
class DynamicList;
template <class T>
template <class T>
class DynamicList
{
private:
Node<T> *head;
public:
class Node
{
public:
T* value;
Node<T> *next;
Node<T> *prev;
Node(T val)
{
next = nullptr;
prev = nullptr;
value = &val;
}
};
DynamicList();
~DynamicList();
void operator+=(const T);
friend std::ostream & operator<< <>(std::ostream &, const DynamicList<T> &);
};
and function defenition:
template <class T>
ostream& operator << (ostream & out , const DynamicList<T> & rhs)
{
Node<T>* nodePtr = rhs.head;
Node<T>* nptr = nodePtr->next;
while(nodePtr != NULL)
{
cout<<*(nodePtr->value)<<" ";
nodePtr = nodePtr->next;
}
out<<endl;
return out;
}
template <class T>
void DynamicList<T>:: operator +=(const T val)
{
Node<T>* nodePtr = nullptr;
T vall = val;
Node<T>* newNode = new Node<T>(vall);
if(!head)
{
head = newNode;
}
else
{
nodePtr = head;
while((nodePtr->next))
{
nodePtr = nodePtr->next;
}
nodePtr->next = newNode;
newNode->prev = nodePtr;
}
Every time I'm calling the opperator it gives a weird output for example using:
for(int i = 1; i <= 3; i++)
{
list += i;
}
cout<<list;
It would give an output like 135727363 135727383 135727383 ,I'd just like to know what I'm doing wrong and possibly how I could solve it
Your problem is here:
T* value;
You are storing the address of a value.
The problem is that you are storing the address of a variable that has gone out of scope.
T vall = val;
Node<T>* newNode = new Node<T>(vall);
The variable vall is local to the function operator += which means after it exists it no longer exists (and can contain anything).
To fix change the node to store the value.
class Node
{
public:
T value; // Notice no star here.
Node<T> *next;
Node<T> *prev;
Node(T const& val) // Add `const&` here to avoid a copy.
{
next = nullptr;
prev = nullptr;
value = val; // Notice no and `&` here
}
};