'Write a procedure to swap the first two nodes of a doubly linked list.'
Can someone explain this thing using images?
void swapFirstTwo() {
if (head != tail) {
DLLNode neck = head.next;
head.next = neck.next;
neck.next = head;
head.prev = neck;
neck.prev = null;
if (tail == neck) // two element list
tail = head;
head = neck;
}
}
Example-1
1<=>2<=>3->null
structure-
1.next = 2;2.next = 3;3.next = null;
1.prev = null;2.prev = 1;3.prev = 2;
To swap the first two elements means to swap their positions. So once the swapping is done, the list will look like this-
2<=>1<=>3->null
This is how the code you have pasted gives the expected result-
neck = head.next;
neck = 2;
neck.next = head;
2.next = 1;
head.prev = neck;
1.prev = 2;
head.next = neck.next;
1.next = 3;
neck.prev = null;
2.prev = null;
Basically, the next and prev pointers of 1 & 2 are exchanged. On adding up all the steps above, you get-
2.next = 1;1.next = 3;3.next = null
2.prev=null;1.prev = 2;3.prev = 2;
But one step missing in the above logic is the head should be pointing to neck. Since, head changes on swapping the elements.
Example-2
In case there's only one element in the list, swapping won't be necessary
Example-3
In case, there are only two elements, along with changing the pointer of head, since tail(end) of the list is maintained, you will have update the tail as well as tail would be pointing to the current head after exchange instead it should point to the current neck.
Related
Node *reverse(Node *head)
{
Node *answer = NULL, *p = head, *address = NULL;
while (p != NULL)
{
address = p;
address->next = answer;
answer = address;
p = p->next;
}
return answer;
}
In order to reverse a singly linked list, you need to keep one node in memory to be able to relink backwards.
It could look like this:
Node* reverse(Node* head) {
if(head) { // must have at least one node
Node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
Node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
return head;
}
Demo
I wrote following code but this is giving only first node's data as output
Because, in reverse() function, you are breaking the link of first node from rest of the list and returning it.
Look at this part of code:
address = p;
address->next = answer;
answer = address;
p = p->next;
In first iteration of while loop this is what happening:
Pointer address will point to head of list (as p is initialised with head) and, in the next statement, you are doing address->next = answer (note that answer is initialised with NULL). So, address->next is assigned NULL. Both, pointer p and pointer address are still pointing same node. After this, you are doing p = p->next, this will assign NULL to p because p->next is NULL. As, p is NULL, the while loop condition results in false and loop exits and function end up returning the first node.
You should assign p to its next before assigning answer to address->next, like this:
while (p != NULL)
{
address = p;
p = p->next; // moved up
address->next = answer;
answer = address;
}
Suggestion:
In C++, you should use nullptr instead of NULL.
Reversing a linked list, in essence, is pretty much flipping the arrows:
Original: A->B->C->D->null
Intermediate: null<-A<-B<-C<-D
Reversed: D->C->B->A->null
void reverseList(void)
{
Node *prev = nullptr;
Node *curr = head;
while (curr)
{
Node *nxt = curr->next;
curr->next = prev;
prev = curr;
curr = nxt;
}
head = prev;
}
The crux of the solution will be to use the previous and current node strategy to loop through the list. On lines two and line 3, I set the prev to null and curr to the head respectively. Next, I set the while loop, which will run until curr is equal to null or has reached the end of the list. In the 3rd and 4th lines of the body of the while loop, I set prev to curr and curr to nxt to help me move through the list and keep the traversal going while keeping track of the previous and current nodes.
I am storing the next of the current node in a temporary node nxt since it gets modified later.
Now, curr->next = prev is the statement that does some work. Flipping of the arrows takes place through this statement. Instead of pointing to the next node, we point the next of the current node to the previous node.
Now, we need to take care of the head node only. On the last line, head=prev, prev is the last node in the list. We set the head equal to that prev node in the list, which completes our code to reverse a list.
Suppose you have any trouble visualizing the algorithm. In that case, you even have the privilege to print the data stored in the current and previous nodes after each line in the while loop for a better understanding.
Hope this helps getting the gist of how we reverse a linked list.
I'm trying to swap 2 adjacent nodes in a linked list (75 and 9 in this case), and every time I run the code, say with a linked list of 75->9->767->2..., I get the whole list just turning to 75->9->75->9->75->9, etc.. I have to update pointers
Your problem is with the lines
nextPtr->next = tempPtr;
nextPtr = tempPtr;
I'm not sure, but i think you only mean to type
nextPtr = tempPtr;
instead.
I guess you are looking for pairwise swap, use this for the same. Let me know if it went fine.
for 75->9->767->2 it produces 9->75->2->762... If you want something different but similar, you can use it and make changes accordingly.
void swap(struct node **head)
{
if (*head == NULL || (*head)->next == NULL)
return;
struct node *prev = *head;
struct node *cur = (*head)->next;
*head = cur;
while (true)
{
struct node *next = cur->next;
cur->next = prev;
if (next == NULL || next->next == NULL)
{
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
cur = prev->next;
}
}
Hint: If you want to swap nodes H (what you're calling hdList) and N (nextPtr) in a linked list you have to make whatever points to H now point to N. You're not keeping track of whatever points to H at all.
That is, suppose you know that part of your list is
... P -> H -> N -> Q ...
and you want to swap H and N. The state of the list after the swap should be
... P -> N -> H -> Q ...
right? But you can't do this because you don't know what used to point to H (i.e. P) so you can make it point to N.
I think you're going to have to go back to the drawing board on this one.
If you want to swap 2 nodes in linked list, why are you trying to swap the pointers and all? Just swap the data in it with the simple swap logic. let the pointers be as it is. If this is not what you want, tell me in detail what exactly you want it to be.
I searched previous asked questions but could not find exactly what I was looking for. I was curious if anyone had any idea on how to delete every other node of a linked list. I have a function called duplicate which take 1 2 3 and turns it into 1 1 2 2 3 3. Deleting every other node would work just fine, no need to compare them or anything. If anyone has any insights. Please don't just post source code.
Heres what I was trying to do but wasn't working.
Node *current;
Node *undo;
for (current = front, undo = current->next->next;
undo != NULL; current = current->next, undo = current->next->next){
current->next = undo;
}
This will output 1 1 2 2 3 3 3
Thank you for any help. I can comment back later to clarify any misconceptions.
Original code:
for (current = front, undo = current->next->next;
undo != NULL;
current = current->next, // this moves current on before you use it's next pointer
undo = current->next->next){
current->next = undo;
}
To fix, without deallocating the unwanted nodes (assumes an even number of nodes):
for (current = front; current != NULL; current = current->next){
current->next = current->next->next
}
To handle odd length lists, and delete memory of removed nodes:
for (current = front; current && current->next ; current = current->next){
undo = current->next;
current->next = current->next->next
delete undo;
}
I would use std::list (or perhaps std::forward_list if so needed) and std::copy_if or std::remove_if in C++11.
Otherwise, remember the address of the pointer to be modified, something like:
Node**undoad = &front;
int cnt=0;
for (current=front; current != NULL; current=current->next) {
if (cnt%2 == 1) {
Node*undo = *undoad;
undoad = ¤t->next;
if (undo) undo->next = current->next;
}
cnt++;
}
However, the above probably is a memory leak: you may need to use delete somewhere.
I've been working for hours trying to get this program to insert values into new nodes or "Player" structures for this program.
The thing is, this takes place inside function main(). My teacher requires me to insert as little code as possible since essentially "everything" is there which allows me to change it.
Here's the original code that stores each new value in the head while putting the older value inside "addNew":
Player * head = NULL;
for(int i=0; i<100; i++)
{
Player * addNew = (Player *)malloc(sizeof(Player));
if(head == NULL)
{
head->len = i;
Player * addNew = (Player *)malloc(sizeof(Player));
head->next = NULL;
}
addNew->next = addNew;
addNew->len = i;
}
Player * p = head;
//do this until 'p' has no address.
for(int i=0; p!=0; i++)
{
printf("%s ", p->str);
p = p->next;
}
Does anyone have any ideas on how to solve this?
IMPORTANT: My teacher would like me to not add any new variables or a tail. Please don't ask.
Update: Here's some older code:
//The head is the last one to hold a value. Therefore it gets pushed to the right.
Player * head = NULL;
Original Algorithm
for(int i=0; i<5; i++)
{
Player * addNew = (Player *)malloc(sizeof(Player));
printf("Insert a string: ");
scanf("%s", addNew->str);
addNew->next = head; //assign head's current address to addNew->next
head = addNew; //assign all of addNew to head
}
Update: Here's a new implementation which doesn't work. I can't really find out where exactly that other for loop should go.
addNew->ID = 1;
addNew->ID += i;
if(head == NULL)
{
head = addNew;
addNew->next = head; //assign head's current address to addNew->next
//head->next = addNew;
}
//head->next = addNew;
addNew->next = head;
//head = addNew; //assign all of addNew to head
printf("%d\n", addNew->ID);
Simple trick: have the list* always point to the last element in the list. And set that last element's next pointer to the start of the list. Now you can always easily find both the start and the end of the list with just one pointer. The start is at list->next. Don't call it tail, just "list".
Right now, you're adding everything to the head of the list. However, you want to add to the tail instead.
You already have a pointer to the head. In addition to that though, you'll also need a pointer to the tail. Can you think of a way to get (and update) it?
You could save a pointer to the tail of the list and instead of saving the next item on each node, save the previous one.
This might not be an option but I thought I'd suggest it anyway. Instead of storing things in a different order, you could leave things stored as they are, but simply change the way you output the values. This would not only be very simple to implement, it would also be a faster during list inserts.
This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).