I have the two functions below and I can get the removeAfter function to work correctly but then when trying to implement the removeBefore function the linked list is not changed at all. Am I missing something? I have made necessary changes, but am still getting the same result: removeBefore does not output any changes to the list.
// remove the node after the node p
void DoublyLinkedList::removeAfter(DListNode &p){
if (isEmpty()){
throw EmptyDLinkedListException("Empty Doubly Linked List");
}
DListNode *to_delete = &p;
to_delete = to_delete->next;
if (to_delete != NULL){
if(to_delete->next != NULL){
to_delete->prev->next = to_delete->next;
}
if(to_delete->prev != NULL){
to_delete->next->prev = &p;
}
if (to_delete == &trailer) {
trailer = *to_delete->prev;
}
}
if (to_delete == NULL){
throw EmptyDLinkedListException("Cannot delete a null pointer");
}
delete to_delete;
}
// remove the node before the node p
void DoublyLinkedList::removeBefore(DListNode &p){
/* Complete this function */
if (isEmpty()){
throw EmptyDLinkedListException("Empty Doubly Linked List");
}
DListNode *to_delete = &p;
to_delete = to_delete->prev;
if (to_delete != NULL){
if (to_delete->next != NULL) {
to_delete->next->prev = to_delete->prev;
}
if (to_delete->prev != NULL) {
to_delete->prev->next = to_delete->next;
}
if (to_delete == &header) {
header = *to_delete->next;
}
}
if (to_delete == NULL){
throw EmptyDLinkedListException("Cannot delete a null pointer");
}
delete to_delete;
}
There are errors in your code.
First off, a linked list is a list of pointers, so it is not customary to pass around nodes by reference. You really should be passing them by pointer instead.
removeAfter() does not account for the possibility that p.next might be NULL upon input (when p is the last node in the list). And it is not updating to_delete's siblings correctly before then deleting to_delete itself. It should look like this instead:
void DoublyLinkedList::removeAfter(DListNode *p)
{
DListNode *to_delete = p->next; //Get to the node after p that is to be deleted
if (to_delete != NULL)
{
if (to_delete->next != NULL) {
to_delete->next->prev = to_delete->prev;
}
if (to_delete->prev != NULL) {
to_delete->prev->next = to_delete->next;
}
// update the tail pointer if to_delete is the tail node...
if (trailer == to_delete) {
trailer = to_delete->prev;
}
delete to_delete;
}
}
removeBefore() is making similar mistakes. It does not account for the possibility that p.prev might be NULL upon input (when p is the first node in the list) or even that it might be the head node of the list. It should look like this instead:
void DoublyLinkedList::removeBefore(DListNode *p)
{
DListNode *to_delete = p->prev; //Get to the node before p that is to be deleted
if (to_delete != NULL)
{
if (to_delete->next != NULL) {
to_delete->next->prev = to_delete->prev;
}
if (to_delete->prev != NULL) {
to_delete->prev->next = to_delete->next;
// update the head pointer if to_delete is the head node...
if (header == to_delete) {
header = to_delete->next;
}
delete to_delete;
}
}
That being said, the logic would be better implemented by centralizing it, eg:
void DoublyLinkedList::remove(DListNode *p)
{
if (p = NULL) return;
if (p->next != NULL) {
p->next->prev = p->prev;
}
if (p->prev != NULL) {
p->prev->next = p->next;
}
if (header == p) {
header = p->next;
}
if (trailer == p) {
trailer = p->prev;
}
delete p;
}
void DoublyLinkedList::removeAfter(DListNode *p)
{
remove(p->next);
}
void DoublyLinkedList::removeBefore(DListNode *p)
{
remove(p->prev);
}
That being said, once you understand how double-linked lists work, you should throw away all of this code and just use the STL std::list class instead, which is a standard double-linked list implementation.
Related
void RemoveDuplicates(Slist& l)
{
if (l.head == NULL) {
return;
}
Node* cur = l.head;
while (cur != NULL && cur->next != NULL) {
Node* prev = cur;
Node* temp = cur->next;
while (temp != NULL) {
if (temp->data == cur->data) {
prev->next = temp->next;
cur->next = prev->next;
temp = prev->next;
}
else {
prev = prev->next;
temp = temp->next;
}
}
cur = cur->next;
}
}
Hi, I want to remove duplicates from linked list (0 is NULL)
input: 1->2->2->4->2->6->0
outPut: 1->2->4->6->0
Result after I run my program is:
1->2->6
Where am I wrong? Please help me
Here is my solution for your problem:
bool alreadyExist(Node head)
{
Node cur = head;
while(cur.next != nullptr)
{
if(cur.next->data == head.data) {
return true;
}
cur = *cur.next;
}
return false;
}
void RemoveDuplicates(Slist& l)
{
if (l.head == nullptr) {
return;
}
Node* head = l.head;
Node* curPtr = l.head->next;
while(curPtr != nullptr)
{
if(alreadyExist(*curPtr) == false)
{
head->next = curPtr;
head->next->prev = head;
head = head->next;
curPtr = curPtr->next;
}
else
{
Node* backup = curPtr;
curPtr = curPtr->next;
// delete duplicate elements from the heap,
// if the nodes were allocated with new, malloc or something else
// to avoid memory leak. Remove this, if no memory was allocated
delete backup;
}
}
}
Important: The destructor of the Node-object is NOT allowed to delete the linked object behind the next and prev pointer.
It results, for your input-example, in the output 1->4->2->6->0. Its not totally exact the order, you want as output, but each number exist only one time within the output. It only add the last time of a duplicate number.
I don't really know, if you use C or C++, but because I prefer C++, I replaced the NULL with nullptr in the code. The delete can be removed, if the objects are not on the HEAP create with malloc or new.
Here using the function returnReverseLinkedList I am returning the reversed linked list of the given linked list. But the problem with this approach is that i lose the original linked list. So I make another fucntion called createReversedLinkedList to make a copy of the original linked list and reverse the copy and maintain possession of both.
unfortunately createReversedLinkedList is giving Runtime error.
obviously my end goal is to check if the given linked list is palindrome or not. This issue is just a stepping stone.
Could someone tell me why?
//Check if a linked list is a palindrome
#include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
node(int data)
{
this->data = data;
this->next = NULL;
}
};
node *returnReverseLinkedList(node *head)
{
// Will Lose original Linked List
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return head;
node *prev = NULL;
node *curr = head;
node *tempNext = head->next;
while (tempNext != NULL)
{
curr->next = prev;
prev = curr;
curr = tempNext;
tempNext = tempNext->next;
}
curr->next = prev;
return curr;
}
node *createReversedLinkedList(node *head)
{
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return NULL;
else
{
node *temp = head;
node *newHead = NULL;
node *newTail = NULL;
while (temp != NULL)
{
node *newNode = new node(temp->data);
if (newHead == NULL)
{
newHead = newNode;
newTail = newNode;
}
else
{
newTail->next = newNode;
newTail = newNode;
}
}
return returnReverseLinkedList(newHead);
}
}
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head);
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false;
cout << "debug 2" << endl;
original = original->next;
reverse = reverse->next;
}
return true;
}
// #include "solution.h"
node *takeinput()
{
int data;
cin >> data;
node *head = NULL, *tail = NULL;
while (data != -1)
{
node *newnode = new node(data);
if (head == NULL)
{
head = newnode;
tail = newnode;
}
else
{
tail->next = newnode;
tail = newnode;
}
cin >> data;
}
return head;
}
void print(node *head)
{
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
int main()
{
node *head = takeinput();
node *revese2 = createReversedLinkedList(head);
print(revese2);
// bool ans = check_palindrome(head);
// if (ans)
// cout << "true";
// else
// cout << "false";
// return 0;
}
As asked by the OP, building a reversed linked is simply done by building as you would a stack (e.g LIFO) rather than duplicating the same original forward chain. For example:
node *createReversedLinkedList(const node *head)
{
node *newHead = NULL;
for (; head; head = head->next)
{
node *p = new node(head->data)
p->next = newHead;
newHead = p;
}
return newHead;
}
Note we're not hanging our copied nodes on the tail of the new list; they're hanging on the head of the new list, and becoming the new head with each addition. That's it. There is no need to craft an identical list, then reverse it; you can reverse it while building the copy to begin with.
A note on the remainder of your code. You have a dreadful memory leak, even if you fix the reversal generation as I've shown above. In your check_palindrome function, you never free the dynamic reversed copy (and in fact, you can't because you discard the original pointer referring to its head after the first traversal:
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head); // only reference to reversed copy
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false; // completely leaked entire reversed copy
original = original->next;
reverse = reverse->next; // lost original list head
}
return true;
}
The most obvious method for combating that dreadful leak is to remember the original list and use a different pointer to iterate, and don't leave the function until the copy is freed.
bool check_palindrome(const node *head)
{
bool result = true;
node *reverse = returnReverseLinkedList(head);
for (node *p = reverse; p; p = p->next, head = head->next)
{
if (p->data != head->data)
{
result = false;
break;
}
}
while (reverse)
{
node *tmp = reverse;
reverse = reverse->next;
delete tmp;
}
return result;
}
I have 2 methods in my program, one finds the node with the value x and another one deletes the node with that value. Here they are:
node*findNode(int x)
{
for (node*p = head; p != NULL; p = p->next)
{
if (p->data == x)
{
return p;
}
}
return NULL;
}
void removeNode(node*tmp)
{
if (tmp == NULL)
{
}
else if (tmp == head)
removeFront();
else if (tmp == tail)
removeBack();
else {
tmp->next->prev = tmp->prev;
tmp->prev->next =tmp->next;
delete tmp;
}
}
void remove(int x)
{
node*tmp = findNode(x);
removeNode(tmp);
}
I know my removeFront and removeBack methods work well. My question is,how could I implement it so instead of deleting only one node with x, it deletes all nodes that contain x in the list. I tried to implement another for loop inside findNode but it didn't work. I am not even sure I can do that.
node*findNode(T x)
{
for (node*p = head; p != NULL; p = p->next)
{
if (p->data == x)
{
node*z = p;
return p;
for (node*i = z->next; i != NULL; i = i->next)
{
if (i->data == x)
return i;
}
return NULL;
}
}
return NULL;
}
My idea was to have a pointer after we find the first value and then do the same process but it didn't work.
So basically if list contains: 10 20 30 30 40 50 , and I use remove(30) it should delete all 30's
You need a loop inside of remove():
void remove(int x)
{
node *p = head;
while (p)
{
node *next = p->next;
if (p->data == x)
removeNode(p);
p = next;
}
}
On a side note: I wouldn't separate removeNode() the way you have. It makes more sense to keep all of the update operations in a single method, eg:
void removeNode(node *tmp)
{
if (!tmp) return;
if (tmp->next) tmp->next->prev = tmp->prev;
if (tmp->prev) tmp->prev->next = tmp->next;
if (tmp == head) head = tmp->next;
if (tmp == tail) tail = tmp->prev;
delete tmp;
}
Then you can implement the other methods in terms of removeNode():
void removeFront()
{
removeNode(head);
}
void removeBack()
{
removeNode(tail);
}
Im making a Queue singly linked list for an assignment. My insert method should add the value at the end of the linked list. My first() method should return the value of the first node in the linked list. Here is my attempt at this:
void QueueList::insert(const BinType & item)
{
try
{
Node *before = head;
Node *after = before->next;
if (numberOfNodes == 0)
{
before->next = tail = CreateNode(item, after);
}
else
{
Node *tmp = head;
while (tmp && tmp->next != NULL) tmp = tmp->next;
Node *tmp1 = CreateNode(item, nullptr);
if (tmp == NULL)
head = tmp1;
else
tmp->next = tmp1;
}
numberOfNodes++;
}
catch (const std::exception err)
{
cerr << "QueueList Error: " << err.what() << endl;
}
}
My first Method
BinType QueueList::first() const
{
return head->item;
}
My Driver
QueueList one;
one.insert(2);
cout<<one.first()<<endl;
When I do this the console prints 0. I am not sure why its not returning 2?
EDIT: class code
#include "QueueList.h"
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
namespace DB{
void QueueList::releaseNodes()
{
Node *del = head;
while (head != nullptr) {
head = head->next;
del->next = nullptr;
delete del;
del = head;
}
tail = nullptr;
numberOfNodes = 0;
}
QueueList::Node* QueueList::CreateNode(const BinType & item, Node * const next)
{
if (new Node(item,next) == nullptr)
{
throw bad_alloc();
}
return new Node(item,next);
}
QueueList::QueueList()
{
head = tail = CreateNode(BinType(), nullptr);
numberOfNodes = 0;
}
QueueList::~QueueList()
{
releaseNodes();
}
void QueueList::insert(const BinType & item)
{
try
{
Node *before = head;
Node *after = before->next;
if (numberOfNodes == 0)
{
before = tail = CreateNode(item, nullptr);
}
else
{
Node *tmp = head;
while (tmp && tmp->next) tmp = tmp->next;
Node *tmp1 = CreateNode(item, nullptr);
if (tmp == NULL)
head = tmp1;
else
tmp->next = tmp1;
}
numberOfNodes++;
}
catch (const std::exception err)
{
cerr << "QueueList Error: " << err.what() << endl;
}
}
BinType QueueList::remove()
{
if (numberOfNodes == 0)
{
throw bad_alloc();
}
Node *del;
del = head->next;
head->next = del->next;
numberOfNodes--;
}
BinType QueueList::first() const
{
return head->item;
}
int QueueList::size() const
{
return numberOfNodes;
}
bool QueueList::isEmpty() const
{
if (head == nullptr)
{
return true;
}
}
}
The issue you had was you were creating a local variable,before, that was a pointer to the head of your linked list. When inserting, you then changed what before was pointing to. Keep in mind, this had no affect on what the head of your list was actually pointing to. You simply changed before to point to a new node instead of head.
In your project, make sure you're updating the head and tail properties of your class, not local pointers that may be pointing to head and tail. Also, in your class constructor,you should have head set to NULL instead of an actual node. Otherwise, isEmpty will not resolve to true upon creation of an empty list.
Since this is a class project, probably best to let you debug other problems I may see so good luck!! Sometime it's helpful to use GDB to step through your code to find out when it does something you didn't intend it to do.
I am currently writing some code which will delete the last node from a linked list, i have the code below; but it is deleting the previous node to the last node; not the last node itself.
Any help will be appreciated:
if(p!=NULL) {
if( p->next!=NULL) {
Student *todel = p->next;
p->next= p->next->next;
delete todel; //free(todel);
} else {
delete p; //If n = 0 && its the last element, delete it
}
}
EDIT:
I have now edited this code to look like the below......it is not working; is it because I am pointing to a NULL vaue, then deleting that null value?
if(p!=NULL) {
if( p->next==NULL) {
delete p;
}
}
Check this one.
if(p!=NULL) {
if ( p->next!=NULL) {
while (1) {
Student *todel = p->next;
if (todel->next == NULL) {
// todel is indeed the last node, delete it
delete todel;
p->next = NULL;
break; // break from infinite while loop that was looking for last node
}
else {
// todel is not last node, go further
p = todel->next;
}
}
} else {
delete p; //If n = 0 && its the last element, delete it
}
}
Try the following instead inside the loop you are using to walk the linked list.
if(p->next!=NULL) {
if (p->next->next == NULL) {// Found the second-to-last-node
delete p->next; // Kill the last node
p->next = NULL; // Make the current node the last node.
}
}
Try this, I didn't test it.
void delete_lastnode(Node* head)
{
Node *p = head;
if (p == NULL) // NULL list
return;
if (p->next == NULL) // Single node list
{
delete head;
head = NULL;
return;
}
while(p->next->next != NULL) // Find the second-last node
{
p = p->next;
}
Node* temp = p->next;
p->next = NULL;
delete temp;
temp = NULL;
}