Trying to finish my doublely linked list program, but I don't really know how to create a node using a class. I've only ever used sctructs.
DoubleNode.h:
#ifndef DOUBLE_NODE_H_
#define DOUBLE_NODE_H_
template<class ItemType>
class DoubleNode
{
private:
ItemType item;
DoubleNode<ItemType>* prev;
DoubleNode<ItemType>* next;
public:
DoubleNode(const ItemType& anItem, DoubleNode<ItemType>* prevPtr, DoubleNode<ItemType>* nextPtr);
~DoubleNode();
ItemType getItem() const;
DoubleNode<ItemType>* getPrev() const;
DoubleNode<ItemType>* getNext() const;
void setPrev(DoubleNode<ItemType>* prevPtr);
void setNext(DoubleNode<ItemType>* nextPtr);
};
#endif
DoubleNode.cpp:
#include "DoubleNode.h"
template<class ItemType>
DoubleNode<ItemType>::DoubleNode(const ItemType& anItem, DoubleNode<ItemType>* prevPtr, DoubleNode<ItemType>* nextPtr) :
item(anItem), prev(prevPtr), next(nextPtr)
{
}
template<class ItemType>
DoubleNode<ItemType>::~DoubleNode()
{
this->prev = this->next = nullptr;
}
template<class ItemType>
ItemType DoubleNode<ItemType>::getItem() const
{
return this->item;
}
template<class ItemType>
DoubleNode<ItemType>* DoubleNode<ItemType>::getPrev() const
{
return this->prev;
}
template<class ItemType>
DoubleNode<ItemType>* DoubleNode<ItemType>::getNext() const
{
return this->next;
}
template<class ItemType>
void DoubleNode<ItemType>::setPrev(DoubleNode<ItemType>* prevPtr)
{
this->prev = prevPtr;
}
template<class ItemType>
void DoubleNode<ItemType>::setNext(DoubleNode<ItemType>* nextPtr)
{
this->next = nextPtr;
}
These two files were provided by my professor, and I need to implement another class called DoubleListInterface.h. I'm working on that right now, but I don't really know if I've even created the nodes right.
Here's my DoubleList.cpp insertFront implementation so far:
template<class ItemType>
bool DoubleList<ItemType>::insertFront(const ItemType& newEntry)
{
DoubleNode<ItemType>* n; // Creating pointer to node
DoubleNode<ItemType>* head;
DoubleNode<ItemType>* tail;
// If list is empty, this is the first node
if (itemCount == 0){
n = new DoubleNode<ItemType>; // Creating node
n->this->item(newEntry); // Putting item in node
n->prev = NULL; // First node, so prev is null
head = n; // Both head and tail would be at this node
tail = n;
itemCount++; // Increment itemCount
}
else{
DoubleNode<ItemType>* temp = new node; // Creating a filling new node
temp->this->item(newEntry);
temp->this->setPrev(head->this->getPrev()); // Set prev to the prev of head pointer
temp->this->getNext() = this->head; // Make next point to the head
head->this->getPrev() = temp; // Point prev of the old head node to the newly created node
head = temp; // Temp is the new head
delete temp; // Delete temp pointer
temp = NULL;
itemCount++; // Increment intemCount
}
return true;
}
I get a lot of errors when I run this, the majority of which are "expected unqualified-id before 'this'" on every place that I use a this pointer. Don't really know what that means either, but I'd really like to know if I'm creating the nodes right. Thanks for anything you can contribute.
You can't point to this.
For example, you wrote
temp->this->item(newEntry);
The correct way to do this is
temp->item(newEntry);
Related
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
}
I am trying to create an insertAfter function where it accepts a value by reference and then inserts that value after the current node. I am unsure how to implement the code.
Below is the header file and what I have tried but it does not compile.
#include <iostream>
#include <string>
class DoublyLinkedList {
public:
DoublyLinkedList();
~DoublyLinkedList();
void append (const string& s);
void insertBefore (const string& s);
void insertAfter (const string& s);
void remove (const string& s);
bool empty();
void begin();
void end();
bool next();
bool prev();
bool find(const string& s);
const std::string& getData() const;
private:
class Node
{
public:
Node();
Node(const string& data);
~Node();
Node* next;
Node* prev;
string* data;
};
Node* head;
Node* tail;
Node* current;
};
void DoublyLinkedList::insertAfter(const string& s)
{
// Node *temp, *var;
//var=(Node *)malloc(sizeof(Node));
if(head == NULL)
{
append(s);
}
temp->data=current;
}
void DoublyLinkedList::append(const string& s)
{
//create a new Node
current = new Node(s);
if (this->empty())//check if it is empty or not
{
this->head = this->tail = current;
}else{
//append to tail
current->prev = tail;
tail->next = current;
tail = current;
}
}
#endif
-Create a new node and store the data passed in. Set the current pointer to head.
Node * newNode = new Node(s);
current=head;
-You must traverse over the LinkedList using a loop which checks the values of each node using 2 pointers, one which trails behind the one that checks the node values.
while(current->data != insertAfter-
>data)
{
current=current->next;}
-Once the proper node is found with current, the loop should stop. Set the new node's next pointer to the insertAfter's next pointer, and the prev pointer to the insertAfter node.
newNode->next = insertAfterNode->next;
newNode->prev = insertAfterNode;
-You then set current's next pointer to the node you'd like to insert.
current->next = newNode;
Also, be sure to add each potential case. If it is the tail that was inserted after, be sure to set the tail pointer to newNode and same if it is inserted at the head. After traversing with the loop, put:
if(tail->data==current->data)
{
tail = newNode;
}
if(head->data==current->data)
{
head=newNode;
}
Edit: because this is a doubly LinkedList, the prev pointer can be implemented in place of trailCurrent, which is not needed at all.
I am attempting to make a queue in c++ using a double linked list. I Have not fully tested everything since i am stuck at the step where you dequeue. I attempted to create a temp node, and move around stuff so when I call delete on the head node in the queue (called queue), and then set the head to a temp node which is the next element, (you can see in the code) but when I call delete, is where it crashes, according to MS Visual studios 2013. Also to add how weird this is, following the stack called, after delete is called, setPrev is called and set the prev node and crashes there. Now I never call this function during any of my destructors deletes so any help will do. I will try my best to understand any answers but I am still new to c++ terminology. Below is my code. Oh one last thing, in main, all I did was call enqueue once, then dequeue once, then delete
Node Class
...
#ifndef TSDNODE_H
#define TSDNODE_H
template <class T>
class DNode
{
private:
DNode<T>* next;
DNode<T>* prev;
T data;
public:
DNode(T);
void setNext(DNode<T>* next);
void setPrev(DNode<T>* prev);
DNode<T>* getNext() const;
DNode<T>* getPrev() const;
T getData() const;
void setData(T data);
~DNode();
};
template <class T>
DNode<T>::DNode(T data)
{
this->next = nullptr;
this->data = data;
this->prev = nullptr;
}
template <class T>
void DNode<T>::setNext(DNode<T>* next)
{
this->next = next;
}
template <class T>
void DNode<T>::setPrev(DNode<T>* prev)
{
this->prev = prev;
}
template <class T>
DNode<T>* DNode<T>::getNext() const
{
return this->next;
}
template <class T>
DNode<T>* DNode<T>::getPrev() const
{
return this->prev;
}
template <class T>
T DNode<T>::getData() const
{
return this->data;
}
template <class T>
void DNode<T>::setData(T data)
{
this->data = data;
}
template <class T>
DNode<T>::~DNode()
{
delete this->next;
delete this->prev;
this->next = nullptr;
this->prev = nullptr;
}
#endif /* TSDNODE_H */
....
Queue Class
....
#ifndef TSQUEUE_H
#define TSQUEUE_H
#include "TSDNode.h"
#include <string>
template <class T>
class Queue
{
private:
DNode<T>* queue;
DNode<T>* tail;
int size;
public:
Queue();
void enqueue(T data);
T dequeue();
~Queue();
};
template <class T>
Queue<T>::Queue()
{
this->queue = nullptr;
this->tail = this->queue;
size = 0;
}
template <class T>
void Queue<T>::enqueue(T data)
{
if (this->tail != NULL)
{
this->tail->setNext(new DNode<T>(data));
this->tail->getNext()->setPrev(this->tail);
this->tail = this->tail->getNext();
}
else
{
this->queue = new DNode<T>(data);
this->tail = this->queue;
}
size++;
}
template <class T>
T Queue<T>::dequeue()
{
T data;
if (this->queue == nullptr)
{
delete this->tail;
delete this->queue;
this->tail = nullptr;
std::string ex = "Exception: Empty Queue\n";
throw ex;
}
else if (this->queue != nullptr)
{
data = this->queue->getData();
DNode<T>* node = this->queue->getNext();
this->queue->setNext(nullptr);
this->queue->setPrev(nullptr);
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
delete this->queue;
this->queue = node;
}
size--;
return data;
}
template <class T>
Queue<T>::~Queue()
{
delete this->queue;
this->queue = nullptr;
this->tail = nullptr;
}
#endif /* TSQUEUE_H */
In your DNode destructor, you don't want to delete the next and prev nodes. You only want to delete this node, not everything it links to.
Remove these lines
delete this->next;
delete this->prev;
Edit: Actually this isn't your problem, because you are clearing out the next and prev values before you delete the node. I still think it is better to not automatically delete the whole chain, but as long as you are consistent with how you handle node deletion it should still work.
You actually problem is that when you dequeue the last node, you still try to set the next pointer of the next node in this line:
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
At this point node is nullptr, so trying to access node->next causes a crash. A simple if test is all you need
if (node != nullptr)
node->setPrev(nullptr);
//--------------------------------------------------- no longer crashes here
Edit 2:
Also note that in the case where the next node in the queue is nullptr, you also want to set the tail to nullptr.
I am new to templates in C++ and am working on a project where I need to implement a Doubly Linked List using a template. However, I can't seem to access the node elements next and previous.
For example, in my destructor, I cannot use curr-> to bring up my options of using next or prev. IntelliSense just says, "No members available." Also, I can only find errors during build time...no red lines, warnings, anything appear beforehand. I am curious as to why this is not working....is it a bug or intended? If it is, where is my template incorrect thus far?
template<class ItemType>
class SortedList
{
public:
SortedList();
~SortedList();
bool Insert (ItemType toAdd);
bool Delete (ItemType toDelete);
void Print();
private:
SortedList ( const SortedList & copyFrom );
SortedList & operator= ( const SortedList & assignFrom );
struct Node
{
Node ( ItemType item, Node * p = NULL, Node * n = NULL )
{ data = item; prev = p; next = n; }
ItemType data;
Node * prev, * next;
};
Node * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list = NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node * curr = list;
while ( curr != NULL )
{
Node * tempNext = curr->next;
delete curr;
curr = tempNext;
}
}
Put the Node struct out of the SortedList like this:
template<typename ItemType>
struct Node
{
Node(ItemType item, Node * p = NULL, Node * n = NULL)
{
data = item; prev = p; next = n;
}
ItemType data;
Node * prev, *next;
};
and then instantiate the template (create the type) inside SortedList like this:
template<class ItemType>
class SortedList
{
public:
//... More code here.
private:
// ... More code here.
Node<ItemType> * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list = NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node<ItemType> *curr = list;
while (curr != NULL)
{
Node * tempNext = curr->next; // Now this will work.
delete curr;
curr = tempNext;
}
}
The logic I have followed
A template, is not a type. You get the type instantiating the template. Hence the type Node Does not exists until you instantiate the template StortedList since the former is inside the latter.
Also the exact type for Node would be SortedList<ItemType>::Node, and there you can see you can't talk about Node, before compiling the code. Thats why IntelliSense don't "see it".
I'm building my own linked list class and I'm having some issues figuring out how to write some functions to help me traverse this list. This is my first time building a linked list from scratch, so if my approach is unconventional please let me know what might be more conventional.
I'd like write a function, within the List class that allows me to increment to the next element called getNext() as well as one that getPrev();
I wrote getNext like this:
T* getNext(){return next;}
However it tells me next is not declared within the scope. I'd also like to write a function that lets me access and modify the object within the list. I was considering using the bracket operator, but first I need to write a function to return the data member. Perhaps If I take a similar approach as I did within my pop functions.. thinking about it now. However, I'd still appreciate any advice.
Here is my List class:
#ifndef LIST_H
#define LIST_H
//List Class
template <class T>
class List{
struct Node {
T data;
Node *next;
Node *prev;
//Constructs Node Element
Node(T t, Node* p, Node* n) { data = (t); prev = (p); next = (n); }
// T *getNext() {return next;}
};
Node *head;
Node *tail;
public:
//Constructor
List() { head = NULL; tail=NULL; }
//Destructor
~List() {
while(head){
Node * temp(head);
head = head->next;
delete temp;
}
}
//is empty
bool empty() const {return (!head || !tail ); }
operator bool() const {return !empty(); }
//Push back
void push_back(T data) {
tail = new Node(data, tail, NULL);
if(tail->prev) //if the node in front of tail is initilized
tail->prev->next = tail;
if( empty() )
head = tail;
}
//Push front
void push_front(T data) {
head = new Node(data, NULL, head);
if(head->next)//if the node following head is initilized
head->next->prev = head;
if( empty() )
tail = head;
};
T pop_back() {
if( empty() )
throw("Error in List: List is empty\n");
Node* temp(tail);
T data(tail->data);
tail = tail->prev;
if( tail )
tail->next = NULL;
else
head = NULL;
delete temp;
return data;
}
T pop_front() {
if (empty())
throw("Error in List: List is empty\n");
Node* temp(head);
T data(head->data);
head = head->next;
if(head)
head->prev=NULL;
else
tail = NULL;
delete temp;
return data;
}
T getNext(){return next;}
};
#endif
getNext should be part of the struct Node and return a Node*
Node* getNext() { return next; }
Then from that you can get the value.
If you have to have it part of the list itself, which I would not recommend it will need to take a parameter of what Node you would like the next of:
Node* getNext(Node* n) {return n->next;}
Again, I recommend the first option.
Here is an approximate whole class with both of these:
template<typename T>
class List {
public:
struct Node {
Node* next, prev;
T data;
//some constructor and stuff
Node* Next() {return next;}
}
//some constructors and other functions
Node* getNext(Node* _n) {return _n->Next();}
}
then to use:
int main() {
List<int> l;
//add some stuff to the list
//get the head of the list
List<int>::Node* head = l.head; //or some corresponding function
//then
List<int>::Node* next = head->Next();
//or
List<int>::Node* next2 = l.getNext(head);
}
for starters getNext() should not return a pointer to the template class, it should return a pointer to the Node structure.
So it should be
Node* getNext(){return next;}
Because it's a member of Node struct and getNext is member of List. You should access it from an object of type Node.