Efficiently swap elements pairwise in a singly linked list - c++

I have written a function in C++ that works fine to swap elements pairwise in a singly linked list. However, I was wondering if there was more efficient way to do the same. To be specific the function I wrote has a case which deals when there are only two elements in the linked list. I was wondering if this case can be omitted and put in the general case. I tried doing that but failed to get the output. Is it possible? Here is my code snippet...
struct Node* swap(struct Node* head){
struct Node* temp = NULL;
struct Node* cur;
struct Node* next;
cur = head;
next = cur->next;
// Empty list.
if(head == NULL){
cout<<"List is empty. \n";
return NULL;
}
// Only one element in the list.
if(next == NULL){
return cur;
}
// If two elements in the list.
else if(next->next == NULL){
cur->next = NULL;
next->next = cur;
return next;
}
// General case.
else{
head = next;
while(cur!=NULL){
if(next == NULL)
break;
if(next->next == NULL)
break;
cur->next = next->next;
next->next = cur;
if(temp == NULL)
temp = cur;
else{
temp->next = next;
temp = cur;
}
cur = cur->next;
next = cur->next;
}
return head;
}
}

Yes, you can encompass the two-element case, the one-element case and the zero-element case in the general case. The loop can begin with
while(cur != NULL && cur->next != NULL)

Unless i'm missing something, it seems Beta's solution should do it.
Also, not an answer but bother me:
if(temp == NULL){
temp = cur;
}
else{
temp->next = next;
temp = cur;
}
If temp ends up as cur anyway you can compress this into
if(temp != NULL){
temp->next = next;
}
temp = cur;

Related

Deleting a key from a circular linked list

void deletenode(string key) {
if (last == NULL) {
cout << "your circular linked list is an empty one" << endl;
}
else {
node* p = last->next;
node* prev = last;
do {
if (p->title == key) {
node* temp = p;
prev->next = p->next;
delete(temp);
}
else {
p = p->next;
prev = prev->next;
}
} while (p != last->next);
}}
I was trying to delete a node with key value. For instance, if node p->title is my key then I want to delete that node. However, I implemented it with other values but the code doesn't seem to work or delete a node with key value from my circular linked list. What is the mistake in the function?
circular linked list value "cat", "dog", "rat", "horse", the key to be deleted was "dog". When I traverse throughout the linked list after the deletion it still printed everything including "dog", which means deletion didn't work.
Anytime you write a "delete from the linked list" function, you have to account for the possibility that you are deleting from the "head" or whatever pointer you are referencing with the list. The common pattern is for the function to return the new head of the list if it changed, else return the current head.
Node* deletenode(Node* head, const string& key) {
// empty list
if (head == nullptr) {
return nullptr;
}
// single item list
if (head->next == nullptr || head->next == head) {
if (head->title == key) {
delete head;
head = nullptr;
}
return head;
}
// two or more item list, possibly circular
Node* prev = head;
Node* current = head->next;
Node* first = current;
while (current && current->title != key) {
prev = current;
current = current->next;
if (current == first) {
break;
}
}
if (current == nullptr || current->title != key) {
return head; // not found
}
prev->next = current->next;
if (current == head) {
head = current->next;
}
delete current;
return head;
}
I don't see the full code so I can't make a comment I tried to implement the function, hope it helps you with the comments.
void deleteNodeWithKey(node* head, string key)
{
node *curr = head;
node *last , *temp;
//Search for last node
while (curr->next != head)
{
curr = curr->next;
}
last = curr;
//If head is the desired key, make head's next new head
//and connect last node to new head
if (head->key == key)
{
temp = head->next;
delete head;
head = temp;
last->next = head;
return;
}
temp = head->next;
//Search for node with the given key
node *prev = head;
while (temp != head)
{
if (temp->key == key)
{
prev->next = temp->next;
delete temp;
return;
}
temp = temp->next;
prev = prev->next;
}
//If function gets here, key was not found
}
I made some changes to your code
void deletenode(string key) {
if (last == NULL) {
cout << "your circular linked list is an empty one" << endl;
}
else {
node* prev = last;
// If head is to be deleted
if (last->title == key) {
while (prev->next != last)
prev = (prev)->next;
prev->next = last->next;
free(last);
last = prev->next;
return;
}
node* p = last->next;
do {
if (p->next->title == key) {
node* temp = p->next;
p->next = temp->next;
delete(temp);
}
else {
p = p->next;
prev = prev->next;
}
} while (p != last->next);
}
}

node not getting deleted if it's the head [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
This is my code, the important part at least. Whenever I run it and try to delete the head node, it won't work (the output will be a large negative number). It will work for all other nodes.
Is it something with my code, or you just can't replace the head?
node* displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
return NULL;
}
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
return head;
}
int main() {
node* head1 = initNode(), * head2=initNode(), * head3 = initNode();
int val;
head1 = input();
head2 = input();
head3 = input();
conca(head1, head2, head3);
cout << "the concatated list is: ";
displayList(head1);
cout << endl<<"enter the value you want to delete: ";
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
return 0;
}
For starters the condition of the while loop
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
must be changed like
while ( cur != nullptr && cur->data != val) {
prev = cur;
cur = cur->next;
}
Also you need indeed to delete the found node like
prev->next = cur->next;
delete cur;
return head;
And in main you have to reassign the pointer to the head node like
head1 = deleteVal(head1, val);
With shown updates the function can look the following way
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while ( cur != NULL && cur->data != val ) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
delete cur;
return head;
}
And in main write
head1 = deleteVal(head1, val);
deleteVal() is coded wrong.
When NOT removing the head node, your while loop will exhibit undefined behavior if val is not found in the list. In that situation, cur will become NULL after the last node is checked, and then the loop will try to access cur->data one more time, which is UB.
You need to swap the conditions of the while statement so that cur is checked for NULL before its data member is accessed:
while (cur != NULL && cur->data != val)
Also, if the while loop does find val in the remaining nodes, you are simply unlinking the found node from the list, but you are not actually delete'ing that node, thus you are leaking its memory.
Try this instead:
node* deleteVal(node* head, int val) {
node *cur, *prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
return cur;
}
// we know the head node doesn't match, no need to
// test it again, so start the loop on the 2nd node...
cur = head->next;
prev = head;
while (cur != NULL && cur->data != val) {
prev = cur;
cur = cur->next;
}
if (cur != NULL) {
prev->next = cur->next;
delete cur;
}
return head;
}
Now, that being said, there are other issues with the code shown.
main() is ignoring the return value of deleteVal(). So, if the node pointed to by head1 were actually removed/deleted from the list, main() has no way of knowing that, and thus ends up passing a now-invalid node* pointer to displayList() afterwards. So, you need to assign the return value of deleteVal() back to head1 to reflect the new list state:
head1 = deleteVal(head1, val);
This is why it is not a good design choice to return a new list pointer by return value (unless you mark it as nodiscard in C++17 and later), as it is too easy to ignore. A better design choice is to pass in the caller's variable by reference/pointer instead, so the function can update the caller's variable directly when needed.
Also, main() is leaking the head1, head2, and head3 nodes when calling input(). You are creating new nodes with initNode(), and then reassigning the pointers to point at new nodes created by input(), thus you lose access to the original nodes from initNode().
In fact, even after calling deleteVal(), you are not freeing any remaining nodes before exiting the program. While it is true that the OS will reclaim all used memory when the program exits, it is best practice to explicitly free anything you allocate.
Also, your deleteVal() is needlessly complex, it can be greatly simplified.
Also, there is no good reason for displayList() to return anything at all.
With that said, try something more like this instead:
void displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
void deleteVal(node* &head, int val) {
node *cur = head, **prev = &head;
while (cur != NULL) {
if (cur->data == val) {
*prev = cur->next;
delete cur;
return;
}
prev = &(cur->next);
cur = cur->next;
}
}
void deleteList(node* &head) {
node *cur = head, *next;
head = NULL;
while (cur != NULL) {
next = cur->next;
delete cur;
cur = next;
}
}
int input() { // <-- return int, not node* !
...
return ...; // <-- just the user's entered value, not a node wrapping the value
}
int main() {
node* head1 = initNode(), *head2 = initNode(), *head3 = initNode();
head1->data = input();
head2->data = input();
head3->data = input();
conca(head1, head2, head3);
cout << "the concatenated list is: ";
displayList(head1);
cout << "enter the value you want to delete: ";
int val;
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
deleteList(head1);
return 0;
}

Remove Duplicates linked list

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.

add element after specifiec element in linked list and delete first element

I tried hard to solve this problem but only managed to partially solve it.
My problem in this method is that I need to add an element after another element:
Example: add 5 1
5 is an element in the linked list but I want to add 1 after 5.
Example: let linked list contains these elements : 2 3 7
I call method to add 1 after 3, add 3 1, so the result assume to be 2 3 1 7, but with my method the result is 2 1 3 7, which is my problem.
Second problem is that I can't deal with the first element:
Example: add 2 1
It acts as if the first element does not exist:
void addNodeAtPos(link *head, int pos,int addelement)
{
link prev=NULL;
link curr =*head;
link newNode = (link)malloc(sizeof(node));
newNode->data = addelement;
while(curr->next != NULL )
{
prev = curr;
curr = curr->next;
if(curr->data == pos)
{
newNode->next = curr;
prev->next = newNode;
break;
}
}
}
My problem here is that I can't remove the first element:
void deletenode(link *head,int s){
bool found = false;
node *curr = *head, *prev=NULL;
while(curr != NULL){
// match found, delete
if(curr->data == s){
found = true;
// found at top
if(prev == NULL){
link temp = *head;
curr->next= prev;
delete(temp);
// found in list - not top
}else{
prev->next = curr->next;
delete(curr);
} }
// not found, advance pointers
if(!found){
prev = curr;
curr = curr->next; }
// found, exit loop
else curr = NULL; }
}
Here's the solution to the first problem
if(curr->data == pos)
{
// tempNode = curr->next;
// improvement as suggested by #Rerito
newNode->next = curr->next;
curr->next = newNode;
break;
}
It appears you are using non-circular doubly linked lists. Thus, both ends of the list are marked with NULL. Now, it seems to me that you use C++ in a very C-esque fashion ... (NULL would'nt be used in C++, there is the nullptr keyword).
I will deal with your issues assuming you are using C instead of C++.
// Note that I pass a link **ptr, NOT a link *ptr ...
void addNodeAtPos(link **head, int pos, int addelement) {
// I am assuming head will be a valid pointer, if not, please add the appropriate checks.
link *newNode = NULL, *cur = *head;
if (NULL == (newNode = malloc(sizeof(link)))
return;
newNode->data = addelement;
while (cur != NULL) {
if (cur->data == pos || NULL == cur->next) {
newNode->next = cur->next;
newNode->prev = cur; // remove this line if there is no prev pointer.
cur->next = newNode;
if (NULL != newNode->next) { // remove this if clause if there is no prev pointer
newNode->next->prev = newNode;
}
break;
}
cur = cur->next;
}
}
You did not specify what you should do if the "position" is not found, I assumed that you just add the element at the end of the list in that case.
Now, considering your issue removing the first element :
void deleteNode(link **head, int el)
{
// I assume you wont pass a `NULL` ptr as #head
link *cur = *head, *prev = NULL;
while (cur != NULL) {
if (cur->data == el) {
next = cur->next;
prev = cur->prev;
free(cur);
if (NULL != next)
next->prev = prev;
if (NULL != prev)
prev->next = next;
else
*head = next;
break;
}
cur = cur->next;
}
}
Why do you need to pass a link **head instead of a link *head ? Because when you are removing the head of the list, you must make sure it won't be accessed anymore and thus you need to update the head pointer you use elsewhere. This is what is made in the *head = next; statement in the above function.
If you are using singly linked list (only a pointer to the next element, not the previous), the solution becomes the following :
void deleteNode(link **head, int el)
{
// I assume you wont pass a `NULL` ptr as #head
link *cur = *head, *prev = NULL, *next = NULL;
while (cur != NULL) {
if (cur->data == el) {
if (NULL != prev)
prev->next = cur->next;
else
*head = cur->next;
free(cur);
break;
}
prev = cur;
cur = cur->next;
}
}

Sorting a Singly Linked List With Pointers

I am trying to sort a singly linked list using bubble sort by manipulating ONLY the pointers, no keys.
The following gets stuck in the for loop and loops infinitely. I don't understand why this is. Can anybody explain to me why the end of the list is not being found?
Node* sort_list(Node* head)
{
Node * temp;
Node * curr;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
temp = curr;
curr = curr->next;
curr->next = temp;
didSwap = true;
}
cout << curr->next->key << endl;
}
}
return head;
}
If I change the code so that the keys (data) are swapped, then the function works properly but for some reason I am not able make it work by manipulating only pointers.
Logical Error, you are creating an infinite loop with following code -
temp = curr;
curr = curr->next;
curr->next = temp;
I,e next_of_current is pointing to current, so curr->next will always be curr and never will be NULL;
Next you should use previous pointer to fix your list because your list can be traversed in a single direction. So, Think -
If A->B->C->NULL; and you make C and B swap then the new list will still point to A->B and next iteration will be wrong ... because you are not modifying your previous next.
So, another implementation may be -
Node* sort_list(Node* head) {
Node * curr;
Node * prev;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
prev = head;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
if (head == curr) {
head = curr->next;
curr->next = head->next;
head->next = curr;
prev = head;
} else {
prev->next = curr->next;
curr->next = prev->next->next;
prev->next->next = curr
}
didSwap = true;
} else if (head != curr) {
prev = prev->next;
}
//cout << curr->next->key << endl; // <- this may cause crash if curr->next now points to NULL; (i,e last element)
}
}
return head;
}
Hope this helps, regards.
You have following problem:
Let you have list with three members: ptr1->ptr2->ptr3. Before swap you have following pointer set: curr=ptr1; curr->next=ptr2; curr->next->next=ptr3. When you perform swap you receive curr=ptr2; curr->next=ptr1; curr->next->next=ptr2.
E.g. you lost ptr3. You need to change code of inner loop with following:
temp = curr;
temp->next = curr->next->next; // Save ptr3
curr = curr->next;
curr->next = temp;
didSwap = true;
The field you want to swap is the value. However, if you swap the node, the next field will change, the question becomes a little more complex, you need keep the next field right. In a word, change value is a simple and good method.
node *sorted_list(node *head) {
node *index1,*index2;
for(index1=head;index1->next!=NULL;index1=index1->next) {
for(index2=index1->next;index2!=NULL;index2=index2->next) {
if(index1->data>index2->data) {
int temp=index1->data;
index1->data=index2->data;
index2->data=temp;
}
}
}
return head;
}