i am trying to make a function that changes the order of the pointers of the nodes so that the original list is reversed.
my solution is based on iterating over the main list, then reversing the order of each 2 adjacent nodes: (n1)->(n2) would be (n1)<-(n2) after the first iteration.
my try:
Node push1(Node* curr) {
if(curr == NULL || *curr == NULL) {
return NULL;
}
Node temp = (*curr)->next;
if(temp == NULL) {
return NULL;
}
(*curr)->next = *curr;
return temp;
}
/*******************************/
void reverse2(Node* head) {
Node curr = *head;
while(curr != NULL) {
curr = push1(&curr);
}
}
PROBLEM: i ran through an infinity loop. i tried to fix that but then the list didn't reverse order. is there a way using this approach of push1() that could work?
NOTE: i am not seeking the solution with 3 pointers or recursion.
This works, but is a bit silly
Node* push1(Node** prev, Node* curr)
{
Node* ret = curr->next;
curr->next = *prev;
(*prev)=curr;
return ret;
}
void reverse2(Node** head)
{
Node* prev = *head;
if(!prev) return;
Node* curr = prev->next;
if(!curr) return;
prev->next = 0;
while(curr)
{
curr = push1(&prev,curr);
}
*head = prev;
}
This is not readable or portable but it does not use recursion or additional variables:
struct list {
list *next;
/* ... */
};
list *
reverse(list *l)
{
list *head = nullptr;
while (l) {
head = (list *) ((uint64_t) head ^ (uint64_t) l->next);
l->next = (list *) ((uint64_t) l->next ^ (uint64_t) head);
head = (list *) ((uint64_t) head ^ (uint64_t) l->next);
l = (list *) ((uint64_t) l ^ (uint64_t) head);
head = (list *) ((uint64_t) head ^ (uint64_t) l);
l = (list *) ((uint64_t) l ^ (uint64_t) head);
}
return head;
}
The trick is to use xor swaps.
This is fairly easy using a std::stack<> data structure in combination with a std::vector<>. Recall that Stacks are a type of container, designed to operate in a LIFO context (last-in first-out), where the elements are inserted and extracted only from one end of the container.
So in your situation you will create a stack, add your nodes to the stack in the order you already have, then popping them back off the stack reverses the order of the nodes.
I have sketched the code to do this but note that it is not tested, you should be able to adapt this idea to you situation:
#include <stack>
#include <vector>
std::vector<Node> reverseNodes(Node* currNode, Node* startNode) {
std::vector<Node> reversed;
std::stack<Node> nodeStack;
// First add nodes to the stack:
for (Node* aNode = currNode; aNode != startNode; aNode = aNode->next) {
nodeStack.push(aNode);
}
// Next add your starting node to the stack (last-in):
nodeStack.push(startNode);
// Popping off of the stack reverses the order:
while (!nodeStack.empty()) {
reversed.push_back(nodeStack.pop());
}
// Return the nodes ordered from last->first:
return reversed;
}
Related
I need to write three separate functions for node deletion in a circular singly linked list (deleteFront(), deleteMiddle() and deleteEnd()). I have to use only tail (last). For some reason, my deleteEnd() function deletes second to the last node. Can anyone please help?
struct node
{
int data;
struct node* next;
};
// some other functions
// 6 -> 5 -> 4 -> 3 -> deleteEnd() does 6 -> 5 -> 3 ->
void deleteEnd(struct node* last)
{
if (last != NULL)
{
if (last->next == last)
last = NULL;
else
{
node* temp = NULL;
node* temp1 = last;
while (temp1->next != last)
{
temp = temp1;
temp1 = temp1->next;
}
temp->next = temp1->next;
delete temp1;
}
}
}
There are several issues with your deleteEnd function:
There is no way that the caller can get the new tail reference, because the tail argument is passed by value. The tail parameter should be a pass-by-reference parameter.
The statement after the loop (in the else block) does not remove the correct node. After the loop, temp1->next will be equal to last, and it should be that node that is removed, yet your code removes temp1. You can fix this by changing the loop condition and initialise the temp and temp1 variables to point to one node further in the list.
The else block does not update tail, yet it is clear that it should, since the original tail node is deleted.
Less of an issue, but in C++ you should not use NULL, but nullptr.
Here is a correction:
void deleteEnd(struct node* &last) // corrected
{
if (last != nullptr)
{
if (last->next == last)
last = nullptr;
else
{
node* temp = last; // corrected
node* temp1 = last->next; // corrected
while (temp1 != last) // corrected
{
temp = temp1;
temp1 = temp1->next;
}
last = temp; // added
temp->next = temp1->next;
delete temp1;
}
}
}
Try This
Explanation : So we are receiving head of the Circular Linked List and taking a curr pointer and pointing it to the head of the CLL.
Then we are taking another pointer and keeping it one step before the curr pointer so that we can point that pointer's next(prev->next) to curr's next(curr->next) and free the curr node.
void deleteTail(Node* &head)
{
Node* curr = head;
Node* prev = NULL;
while(curr->next != head)
{
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
curr->next = NULL;
delete curr;
I still struggle with the recursion technique to solve the problem. I know there are nicer ways to solve my problem below of reversing a linked list. Most of the ways that I have seen, start to reverse the pointers by going from the head to the tail, either by using iteration or recursion.
I am trying for interest to reverse the list by first finding the last node in the list recursively and then changing the pointers everytime the function returns.
What am I doing wrong below exactly? Or will this method even work , without the need to pass more parameters to the recursive function? Thanks in advance for your help.
struct Node
{
int data;
struct Node *next;
};
Node* Reverse(Node *head)
{
static Node* firstNode = head;
// if no list return head
if (head == NULL)
{
return head;
}
Node* prev = NULL;
Node* cur = head;
// reached last node in the list, return head
if (cur->next == NULL)
{
head = cur;
return head;
}
prev = cur;
cur = cur->next;
Reverse(cur)->next = prev;
if (cur == firstNode)
{
cur->next = NULL;
return head;
}
return cur;
}
EDIT : Another attempt
Node* ReverseFromTail(Node* prev, Node* cur, Node** head);
Node* ReverseInit(Node** head)
{
Node* newHead = ReverseFromTail(*head, *head, head);
return newHead;
}
Node* ReverseFromTail(Node* prev, Node* cur, Node** head)
{
static int counter = 0;
counter++;
// If not a valid list, return head
if (head == NULL)
{
return *head;
}
// Reached end of list, start reversing pointers
if (cur->next == NULL)
{
*head = cur;
return cur;
}
Node* retNode = ReverseFromTail(cur, cur->next, head);
retNode->next = cur;
// Just to force termination of recursion when it should. Not a permanent solution
if (counter == 3)
{
cur->next = NULL;
return *head;
}
return retNode;
}
Finally Solved it :
Node* NewestReverseInit(Node* head)
{
// Invalid List, return
if (!head)
{
return head;
}
Node* headNode = NewestReverse(head, head, &head);
return headNode;
}
Node* NewestReverse(Node *cur, Node* prev, Node** head)
{
// reached last node in the list, set new head and return
if (cur->next == NULL)
{
*head = cur;
return cur;
}
NewestReverse(cur->next, cur, head)->next = cur;
// Returned to the first node where cur = prev from initial call
if (cur == prev)
{
cur->next = NULL;
return *head;
}
return cur;
}
I will not give you the code, I will give you the idea. You can implement the idea in the code.
The key to all recursion problems is to figure out two cases: repetition step and end case. Once you do this, it works almost as if magically.
Applying this principle to reversing a linked list:
End case: the list of one element is already reversed (this is straightforward) and returning the element itself
Repetition case: Given list L, reversing this least means reversing an L', where L' is the L' is the list without the very first element (usually called head), and than adding the head as the last element of the list. Return value would be the same as a return value of the recursive call you just made.
It can be done. The key in understanding recursion is What is the starting point?
Usually I create a "starting" function which prepares the first call. Sometimes it is a separate function (like in non OO implemnatation at bottom). Sometimes it's just a special first call (like in example below).
Also the key is in remembering variables before they change and what is the new head.
The new head is the last element of the list. So You have to get it up from the bottom of the list.
The nextelement is always your parent.
Then the trick is to do everything in the correct order.
Node* Reverse( Node* parent) // Member function of Node.
{
Node* new_head = next ? next->Reverse( this )
: this;
next = parent;
return new_head;
}
You call the function with: var.Reverse( nullptr);
Example:
int main()
{
Node d{ 4, nullptr };
Node c{ 3, &d };
Node b{ 2, &c };
Node a{ 1, &b };
Node* reversed = a.Reverse( nullptr );
}
So what is happening here?
First we create a linked list:
a->b->c->d->nullptr
Then the function calls:
a.Reverse(nullptr) is called.
This calls the Reverse on the next node b.Reverse with parent a.
This calls the Reverse on the next node c.Reverse with parent b.
This calls the Reverse on the next node d.Reverse with parent c.
d doesn't have next node so it says that the new head is itself.
d's next is now it's parent c
d returns itself as the new_head.
Back to c: new_head returned from d is d
c's next is now it's parent b
c returns the new_head it recieved from d
Back to b: new_head returned from c is d
b's next is now it's parent a
b returns the new_head it recieved from c
Back to a: new_head returned from b is d
a's next is now it's parent nullptr
a returns the new_head it recieved from b
d is returned
Non object oriented implementation;
Node* reverse_impl(Node* parent)
{
Node* curr = parent->next;
Node* next = curr->next;
Node* new_head = next ? reverse_impl( curr )
: curr;
curr->next = parent;
return new_head;
}
Node* reverse(Node* start)
{
if ( !start )
return nullptr;
Node* new_head = reverse_impl( start );
start->next = nullptr;
return new_head;
}
Here's a full implementation I wrote in 5 minutes:
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
struct Node* Reverse(struct Node *n)
{
static struct Node *first = NULL;
if(first == NULL)
first = n;
// reached last node in the list
if (n->next == NULL)
return n;
Reverse(n->next)->next = n;
if(n == first)
{
n->next = NULL;
first = NULL;
}
return n;
}
void linked_list_walk(struct Node* n)
{
printf("%d", n->data);
if(n->next)
linked_list_walk(n->next);
else
printf("\n");
}
int main()
{
struct Node n[10];
int i;
for(i=0;i<10;i++)
{
n[i].data = i;
n[i].next = n + i + 1;
}
n[9].next = NULL;
linked_list_walk(n);
Reverse(n);
linked_list_walk(n+9);
}
Output:
0123456789
9876543210
I don't see solution to this specific question on stackoverflow. So I'm posting this.
My requirement is to delete all the nodes on the right of a linked list when a value greater than 'x' is encountered?
For Ex.
Sample Input:
Linked list has values: 5 1 2 6 and x = 5
Output: 5 1 2
Sample Input
Linked list has values: 7 1 2 6 and x = 6
Output: null (since 7 is greater than 6, it should delete all the nodes on the right)
Sample Input:
Linked list has values: 5 4 7 6 and x = 6
Output: 5 4
I came up with this solution, but I'm trying to find an optimal solution
//head is the root node, nodes greater that "value" should be deleted
Node Delete(Node head, int value) {
// Complete this method
Node cur = head;
Node prev = null;
if(cur == null)
return head;
if(cur != null && cur.data > value )
{
while(cur != null)
{
prev = cur;
cur = cur.next;
}
prev.next = cur;
head = prev;
return head;
}
else
{
while(cur != null && cur.data <= value)
{
prev = cur;
cur = cur.next;
}
if(cur != null && cur.data > value)
{
while(cur != null)
{
cur = cur.next;
}
prev.next = cur;
return head;
}
prev.next = null;
return head;
}
}
Here is a simple O(n) solution in Javascript-style pseudocode,
with several identifiers renamed for clarity.
function deleteGreater(head, value) {
if (head == null) return null;
if (head.data > value) {
deallocate(head); //discard the entire list
return null;
}
var current = head;
while (true) {
if (current.next == null) return head; //end of list
if (current.next.data > value) break;
current = current.next;
}
deallocate(current.next); //discard the rest of the list
current.next = null;
return head;
}
I trust you can convert it to any language you want.
For languages with garbage collection, you can remove the deallocate() calls.
For languages without garbage collection, override the object's deallocation method to make sure that it also deallocates the next property.
In language like Java which have garbage collection, it is as simple as to set the next of last element to null which in worst case will be of O(n) (which will happen when matched with last element)
Node deleteGreaterThan(Node head, int value){
if(head==null || head.data>value)return null;//if head is itself greater than value
Node temp = head;
while(temp.next != null && temp.next.data<=value){
temp= temp.next;
}
temp.next = null;
return head;
}
head = deleteGreaterThan(head, 5);
I guess in language like c, you might have to explicitly delete each element and free the memory, no experience with c, so can't say much, even in that case it will only be O(n)
Like #100rabh said, in a language without garage collection you need to free every single node you allocated. Here is an example in C of how to do that. Notice that calling Delete is still O(n) because we actually update the previous node's next pointer while freeing the current node.
#include <malloc.h>
#include <stdio.h>
struct _Node {
struct _Node *next;
int data;
};
typedef struct _Node Node;
Node* Build(int value)
{
int i;
Node *ptr, *head=NULL;
for (i=1; i<value; i++)
{
if(head==NULL)
{
head=malloc(sizeof(Node));
ptr=head;
}
else
{
ptr->next=malloc(sizeof(Node));
ptr=ptr->next;
}
ptr->data=i;
ptr->next=NULL;
printf("Build: node=%p {data=%d next=%p}\n", ptr, ptr->data, ptr->next);
}
return head;
}
void Print(Node *head)
{
Node *ptr=head;
while(ptr!=NULL)
{
printf("Print: node=%p {data=%d, next=%p}\n", ptr, ptr->data, ptr->next);
ptr=ptr->next;
}
}
/*
* We can't pass head or ptr->next directly
* Because then we can't update it's value when we free what it points to
* So we pass the pointer to head or ptr->next instead
* Here we actually update head or ptr->next to point to the next node until we are finished
*/
void Free(Node **ptr)
{
Node *temp;
if(ptr==NULL) return;
while(*ptr!=NULL)
{
temp=*ptr;
*ptr=(*ptr)->next;
printf("Free: node=%p {data=%d next=%p}\n",temp,temp->data,temp->next);
temp->data=-temp->data;
temp->next=NULL;
free(temp);
}
}
/*
* We can't pass head or ptr->next directly
* Because then we can't update it's value when we free what it points to
* So we pass the pointer to head or ptr->next instead
* Nothing gets updated in this function - Free does all the updating
*/
void Delete(Node **ptr, int value)
{
if(ptr==NULL) return;
while(*ptr!=NULL)
{
if((*ptr)->data>value)
{
printf("Delete: node=%p {data=%d node=%p}\n",*ptr,(*ptr)->data,(*ptr)->next);
Free(ptr);
return;
}
ptr=&(*ptr)->next;
}
}
int main(void)
{
Node *head=Build(10);
Print(head);
Delete(&head, 5);
Print(head);
Free(&head);
return 0;
}
I am learning circular linked list. I face a problem when calling deleteNodeByKey() to remove head node. It works for the rest of the nodes for remove. Why is it not working if remove node is head?
#include <iostream>
#include <stdlib.h>
using namespace std;
/* structure for a node */
struct node
{
int data;
struct node *next;
};
/* Function to insert a node at the begining of a Circular
linked list */
void push(struct node **head_ref, int data)
{
struct node *ptr = (struct node*)malloc(sizeof(struct node));
ptr->data = data;
ptr->next = *head_ref;
struct node *temp = *head_ref;
/* If linked list is not NULL then set the next of last node.
It is going to last node by circling 1 times.
*/
if(*head_ref != NULL){
while(temp->next != *head_ref){
temp = temp->next;
}
//set last node by ptr
temp->next = ptr;
}
else{
// 1 node circular linked list
ptr->next = ptr;
}
// after push ptr is the new node
*head_ref = ptr;
}
//get the previous node
struct node* getPreviousNode(struct node* current_node){
struct node* prev = current_node;
while(prev->next != NULL && prev->next->data != current_node->data ){
prev = prev->next;
}
return prev;
}
/* Given a reference (pointer to pointer) to the head of a list
and a key, deletes the first occurrence of key in linked list */
void deleteNodeByKey(struct node **head_ref, int key)
{
// Store head node
struct node* current_node = *head_ref, *prev;
while(current_node != NULL && current_node->data != key){
current_node = current_node->next;
}
if(current_node == NULL){
return;
}
//Removing the node
if(current_node->data == key){
prev = getPreviousNode(current_node);
prev->next = current_node->next;
current_node->next = NULL;
free(current_node);
return;
}
}
/* Function to print nodes in a given Circular linked list */
void printList(struct node *head)
{
struct node *temp = head;
if(head != NULL){
/*
do-while because at 1st temp points head
and after 1 rotation temp wil come back to head again
*/
do{
cout<<temp->data<<' ';
temp = temp->next;
}
while(temp != head);
cout<<endl;
}
}
int main() {
/* Initialize lists as empty */
struct node *head = NULL;
/* Created linked list will be 11->2->56->12 */
push(&head, 12);
push(&head, 56);
push(&head, 2);
push(&head, 11);
cout<<"Contents of Circular Linked List"<<endl;
printList(head);
deleteNodeByKey(&head, 11);
printList(head);
return 0;
}
Here is the code link: Source Code
Head node should not be the part of linked list, it should be a separate node which holds the address of the first node of the linked list. So when yo delete the first node make the Head point to the next of the first node and when you follow this structure the head-node will be same like other nodes.
declare head like this:
struct node* head;
head = *first;
To delete first
head = head->next;
free(first);`
In order to get around issues pertaining to deletion of head. I always found it useful to create a dummy node and set your head pointer to that.
node dummy;
dummy.next = *head_ref;
// Store head node
struct node* current_node = &dummy, *prev = &dummy;
current_node = current_node->next;
Once you are done with the operation set the head back to dummy.next. In this way you no longer need to keep track of the special case head, it can be treated as a normal node. Your code modified here: deletion with dummy node
inside deleteNodeByKey() function i add an if() block to re assign head node to it's next node:
//Removing the node
if(current_node->data == key){
//following if() is newly added
//key is inside head node
if(current_node == *head_ref ){
//changing the head point to next
*head_ref = current_node->next;
}
prev = getPreviousNode(current_node);
prev->next = current_node->next;
current_node->next = NULL;
free(current_node);
return;
}
I am trying to merge two linked lists. One issue I have is how I can have my while loop continue to run even after 1 list reaches the end.
E.G: List1 values: 1, 3;
List 2 values: 2,6,7,8;
Ideally the output would be: 1,2,3,6,7,8
Currently my output is more like 1,2,3 (list1 has reached the end so the loop stops and the other list 2 values don't get added to the list).
Also, I would like for my merge to not be destructive to the original 2 lists that I merge, how can I accomplish this?
struct Node
{
int value;
Node *next;
};
void addNode(Node* &head, int x)
{
Node* temp = new Node;
temp->value = x;
temp->next = nullptr;
if(!head)
{
head = temp;
return;
}
else
{
Node* last = head;
while(last->next)
last=last->next;
last->next = temp;
}
}
void merge(Node * &head1, Node * &head2, Node * &head3)
{
while (head1 != nullptr && head2 != nullptr)
{
if (head1->value < head2->value)
{
addNode(head3, head1->value);
head1 = head1->next;
}
else
{
addNode(head3, head2->value);
head2 = head2->next;
}
}
}
Main function:
int main()
{
Node *head = nullptr;
Node *head2 = nullptr;
Node *head3 = nullptr;
for (int i=0; i<=8; i+=2)
addNode(head, i);
for (int i=1; i<=5; i++)
addNode(head2, i);
merge(head, head2, head3);
printList(head);
printList(head2);
printList(head3);
system("PAUSE");
return 0;
}
Nikos M. answered your first question, his answer is fine, so I won't repeat it. This answer addresses your second question:
Also, I would like for my merge to not be destructive to the original 2 lists that I merge, how can I accomplish this?
The answer is simple: Don't pass head1 and head2 by reference:
void merge(Node * head1, Node * head2, Node * &head3)
In fact, I would recommend making head1 and head2 const pointers:
void merge(const Node * head1, const Node * head2, Node * &head3)
The while loop exits as soon as either head1 or head2 becomes null. I think you want to add an extra piece of code to just append all remaining elements from the non-empty list (Im assuming they're already sorted).
Node* lastElements = list1 != nullptr ? list1 : list2;
while( lastElements != nullptr )
{
addNode(list3, lastElements->value);
lastElements = lastElements->next;
}
Add a constructor to Node so that next is always initialised to nullptr. I originally read code wrong an thought you'd missed this initialisation but adding a constructor will simplify your code and mean you wont forget to initialise next pointer if you create nodes elsewhere.
Node( int initValue)
: value(initValue)
, next(nullptr)
{}
and the start of your addNode function becomes 1 line instead of 3.
Node* temp = new Node(x);
Dont pass in reference to head1 and head2 pointers if the merge is not to be destructive. So something like this.
void merge( const Node* head1, const Node* head2, Node3*& outHead3)
{
//copy pointers in order to iterate through list
Node* current1 = head1;
Node* current2 = head2;
while( current1 != nullptr && current2 != nullptr)
{
//as before with relevant name changes
.
.
.
}
Node* lastElements = current1 != nullptr ? current1 : current2;
while( lastElements != nullptr )
{
addNode(outHead3, lastElements->value);
lastElements = lastElements->next;
}
}
you forget to merge any remaining items, use this:
// dont pass head1, head2 by reference in method call
void merge(Node * head1, Node * head2, Node * &head3)
{
// and/or use other variables to avoid changing head1, head2
Node * list1 = head1;
Node * list2 = head2;
while (list1 != nullptr && list2 != nullptr)
{
if (list1->value < list2->value)
{
addNode(head3, list1->value);
list1 = list1->next;
}
else
{
addNode(head3, list2->value);
list2 = list2->next;
}
}
// merge any remaining list1 items
while (list1 != nullptr)
{
addNode(head3, list1->value);
list1 = list1->next;
}
// merge any remaining list2 items
while (list2 != nullptr)
{
addNode(head3, list2->value);
list2 = list2->next;
}
}