I've written code to insert elements into a circular doubly linked list and to display these elements. I'm supposed to also be able to delete the tail node from the the list, as well as search the list for a specific element.
This is my working code for add and print:
void Circular_DLList::add_to_tail(int a)
{
DLLNode *temp = new DLLNode;
temp->info = a;
if (is_empty()) {
tail = temp;
temp->next = tail;
temp->prev = tail;
}
else {
temp->next = tail->next;
temp->prev = tail;
tail = temp;
tail->prev->next = temp;
}
}
void Circular_DLList::print_list()
{
DLLNode *ptr;
ptr = tail->next;
do {
cout<< ptr->info << endl;
ptr = ptr->next;
}
while(ptr != tail->next);
}
No matter what I write for the delete_from_tail function, it causes a segmentation fault:11. This is my attempt for the function (which throws the error).
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
tail = tail->prev;
delete tail->next;
tail->next = NULL;
}
return a;
}
Any advice as to how to fix this would be fantastic. I've tried debugging but I can't seem to figure out the issue or where exactly it's even related to.
Thanks
The issue is pretty obvious if you look at it closely. Your delete function is breaking the circular chain of the Link list. How so? See your delete function below:
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
DLLNode *temp;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
tail = tail->prev;
delete tail->next;
tail->next = NULL;
}
return a;
}
In the else-condition you are setting tail->next = NULL which is actually the bug and hence breaks the chain. So when print is called it assumes that circular chain is intact and hence accidently tries to access a NULL pointer which in turn leads to segmentation fault.
The Fix is very simple see the below code:
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
temp = tail;
tail = tail->prev;
tail->next = temp->next; // To maintain the circular chain
tail->next->previous = tail; // Since this element's previous also point to the node about to be deleted
delete temp;
temp = NULL;
}
return a;
}
Related
I'm writing a class of linked list, I feel that for the member function that used to delete specific element might cause the memory leak. The code is below.
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
void DelElem(int locat)
{
int j{1};
node* tmp = new node;
if (locat == 1)
{
tmp = head->next;
head = tmp;
delete tmp;
}
else
{
node* n = head;
while (j < locat - 1)
{
n = n->next;
j++;
}
tmp = n->next;
n->next = tmp->next;
delete tmp;
}
}
For function 'DelElem', I firstly created a pointer tmp by new operator. However, I assign different address for it which means I lost the original one at the initialization.
How can I fix this problem?
There are few issues with your instance of code, I have corrected that:-
As pointed by others, you are not required to use `new` keyword to declare a pointer.
When one tries to delete the first node of the linked list, then according to your code, it will delete the second node, because of the following
tmp = head->next;
head = tmp;
delete tmp;
Here, tmp is initially pointing to second node,because head->next refers to 2nd node. So instead of that, it should have been like this:-
tmp = head;
head = head->next;
delete tmp;
Now, tmp will point to 1st node, in second line, head will point to 2nd node, and then the first node, pointed by tmp gets deleted.
Here is the corrected version of code:-
struct node {
int data;
node* next;
};
class linked_list {
private:
node *head, *tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node* tmp = new node;
tmp->data = n;
tmp->next = NULL;
if (head == NULL) {
head = tmp;
tail = tmp;
}
else {
tail->next = tmp;
tail = tail->next;
}
}
void DelElem(int locat)
{
int j{ 1 };
node* tmp;
if (locat == 1) {
tmp = head;
head = head->next;
delete tmp;
}
else {
node* n = head;
while (j < (locat - 1)) {
n = n->next;
j++;
}
tmp = n->next;
n->next = tmp->next;
cout << tmp->data;
delete tmp;
}
}
};
when the destructor of 'class LL' ~LL() gets called for this circular singly linked-list, the program crashes instead of freeing up the heap space of the pointer. How can I solve this problem?
class Node {
public:
int data;
Node *next;
};
class LL {
private:
Node *head, *tail;
public:
LL() {
head = NULL;
tail = NULL;
}
// destructor
~LL() {
Node *p = head;
while (p->next != head) {
p = p->next;
}
while (p != head) {
p->next = head->next;
delete head;
head = p->next;
}
if (p == head) {
delete head;
head = nullptr;
}
}
// circular singly Linked list
void createLL() {
int n, x;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
Node *t = new Node;
t->data = x;
t->next = NULL;
if (head == NULL) {
head = tail = t;
} else {
tail->next = t;
tail = t;
}
}
tail->next = head;
}
There are a few issues with the linked list.
The linked list's destructor assumes that head isn't null, when there is a possibility that it could be. Make sure to check that head isn't null before trying to clean up memory. Once that is done, it looks like your original destructor should work.
The function createLL will invoke undefined behavior if the user enters a size less than or equal to 0.
Specifically this line tail->next = head;
TreateLL is a misnomer as it doesn't actually 'create' a new list in the expected sense. The contents aren't cleared, and thus n elements are appended to the end of the current list.
Also, a circularly linked list can be created with just a single tail pointer.
However, getting your implementation of a circular linked list to work looks like this
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
};
class LL {
private:
Node* head, * tail;
public:
LL() : head(nullptr),
tail(nullptr) {
}
~LL() {
if (head) {
Node* p = tail;
while (p != head) {
p->next = head->next;
delete head;
head = p->next;
}
if (p == head) {
delete head;
head = nullptr;
}
}
}
void storeUserInput() {
int n, x;
cin >> n;
if (n <= 0) {
return; //no input to retrieve.
}
for (int i = 0; i < n; i++) {
cin >> x;
Node* t = new Node;
t->data = x;
t->next = nullptr;
if (head == nullptr) {
head = tail = t;
}
else {
tail->next = t;
tail = t;
}
}
tail->next = head;
}
};
int main() {
LL l;
l.storeUserInput();
char response;
std::cin >> response;
}
It seems that you have access C++ 11 or above compiler, if so then you should be using nullptr in place of NULL as it is a definitive pointer type. See more here
You can do it in two steps:
Make the list non-circular. This has two sub-steps:
Detect the loop. There are published algorithms to do this. Edit: Your list has a tail pointer, so there is no need to search for it in your case.
Point the back referencing node to null (or sentinel)
Delete the list which is now non-circular in a loop. This is trivial.
While trying to delete in a loop your circular reference will lead to deleted memory and will have undefined behavior. So first consider breaking the circulatiry:
tail->next = 0;
Then delete in a loop
Node* p = head;
while(p)
{
Node* temp = p;
p = p->next;
delete temp;
}
By the way. tail->next will always point to the head. So you always will have both, the head and the tail in the same pointer. So you can clean the memory like this:
Node* p = tail->next; //this is head
tail->next = 0;
while(p)
{
Node* temp = p;
p = p->next;
delete temp;
}
This is the first question that I'm posting on StackOverflow, so forgive me if it seems kinda choppy.
For my computer science class, we're working with a double linked list for the current assignment. One of the functions required is an insert function.
I actually found an insert function on StackOverflow earlier this week, but it was set up to use structures inside of the main file instead of separate class files like this project is using. I think the function can work, but I'm not sure what alterations I need to make so that it can work with class files instead.
LinkedList.h member data
private:
Node *head, *tail;
mutable Node *it;
int count;
Insert function
bool LinkedList::insert(const string & str) const
{
LinkedList * tempVar;
if (hasMore) {
resetIterator();
}
else {
Node * temp = new Node;
//temp = str;
temp->data = str;
temp->next = it;
temp->prev = nullptr;
it->prev = temp;
it = temp;
}
if (it != nullptr) {
Node * current = it;
Node * previous = nullptr;
Node * tempNode = nullptr;
while (current->next != nullptr) {
tempNode = current->next;
if (current->data > tempNode->data) {
swap(current->data, tempNode->data);
}
else {
previous = current;
current = current->next;
}
}
tempVar->count += 1;
}
return false;
}
I haven't been able to test it yet due to not knowing what alterations are needed, but the function should insert strings that are passed into the argument into the linked list, as well as sort them in a dictionary style. Right now the only error is that temp = str; not working, and I'm not entirely sure what I need to do to get it to work.
Try something more like this:
bool LinkedList::insert(const string & str)
{
Node * current = head;
while ((current) && (current->data < str))
current = current->next;
Node *newNode = new Node;
newNode->data = str;
newNode->next = nullptr;
newNode->prev = nullptr;
if (current)
{
if (current->previous)
{
current->previous->next = newNode;
newNode->previous = current->previous;
}
current->previous = newNode;
newNode->next = current;
if (current == head)
head = newNode;
}
else
{
if (!head)
head = newNode;
if (tail)
{
tail->next = newNode;
newNode->previous = tail;
}
tail = newNode;
}
count += 1;
return true;
}
That being said, you really should be using the standard std::list container instead of implementing a double-linked list manually.
How do I make my program print the Linked List backwards? I got the printForward function working fine but the printBackwards function just doesn't seem to do anything. I think I'm on the right track but I'm a little stuck right now. I think the while loop isn't running because temp is NULL for some reason.
Any help would be great.
Thanks
List.h
#include <iostream>
using namespace std;
class LinkedList
{
private:
struct Node
{
int data;
Node * next;
Node * prev;
};
Node * head, *tail;
public:
LinkedList();
bool addAtBeginning(int val);
bool remove(int val);
void printForward() const;
void printBackward() const;
};
#endif
List.cpp
#include "List.h"
LinkedList::LinkedList()
{
head = NULL;
tail = NULL;
}
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
head = temp;
return false;
}
bool LinkedList::remove(int val)
{
return false;
}
void LinkedList::printForward() const
{
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
void LinkedList::printBackward() const
{
Node* temp = tail;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->prev;
}
cout << endl;
}
app.cpp
#include "list.h"
int main()
{
LinkedList aList;
aList.addAtBeginning(3);
aList.addAtBeginning(10);
aList.addAtBeginning(1);
aList.addAtBeginning(7);
aList.addAtBeginning(9);
aList.addAtBeginning(12);
aList.printForward();
aList.printBackward();
system("pause");
return 0;
}
I find it a bit odd that you only have an addAtBeginning method, and no method to add at the end, the latter which I would consider to be normal use of a linked list. That being said, I think the immediate problem here is that you never assign the tail to anything. Try this version of addAtBeginning:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
if (head != NULL)
{
head->prev = temp;
}
if (head == NULL)
{
tail = temp;
}
head = temp;
return false;
`}
The logic here is that for the first addition to an empty list, we assign the head and tail to the initial node. Then, in subsequent additions, we add a new element to the head of the list, and then assign both the next and prev pointers, to link the new node in both directions. This should allow you to iterate the list backwards, starting with the tail.
Update addAtBeginning function with given:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->prev = temp->next = NULL;
// If adding first node, then head is NULL.
// Then, set Head and Tail to this new added node
if(head == NULL){
// If this linked list is circular
temp->next = temp->prev = temp;
head = tail = temp;
}else{ // If we already have at least one node in the list
// If this linked list is circular
temp->prev = head->prev;
temp->next = head;
head->prev = temp;
head = temp;
}
return false;
}
But remember, if you copy this function with the parts that it makes this list circular, you will get an infinite loop. So, either change print function or dont copy that parts.
I've written a destructor for a doubly linked list which is not working properly. There's a loop to delete the values. The line-of-control comes out of the that loop but the program doesn't finish. I mean, the main does not end.
Never mind, I figured it out.
You can write the destructor cimpler. For example
LinkedList::~LinkedList()
{
for ( ListItem *node = head; node; )
{
ListItem *temp = node;
node = node->next;
delete temp;
}
head = nullptr;
}
Or
LinkedList::~LinkedList()
{
while ( head )
{
ListItem *temp = head;
head = head->next;
delete temp;
}
head = nullptr;
}
First: move delete node; line.
If only head exist it makes error.
LinkedList::~LinkedList() {
ListItem* node = head;
ListItem* temp = NULL;
if (head != NULL && head->next == NULL) {
delete head;
} else {
while (node->next) {
temp = node;
node = node->next;
delete temp;
}
delete node;
}
}
Or remove if statment.
LinkedList::~LinkedList() {
ListItem* node = head;
ListItem* temp = NULL;
while (node->next) {
temp = node;
node = node->next;
delete temp;
}
delete node;
}