c: linked list: how to write a node swapping function? - c

here's my function:
void switchnodes(NODE **A)
{
if((*A)->next)
{
NODE *first = pop(A);
NODE *second = pop(A);
push(A,first);
push(A,second);
}
}
push and pop:
void push(NODE **top,NODE *nnew)
{
nnew->next=*top;
*top=nnew;
}
NODE * pop(NODE **top)
{
NODE *remove = *top;
*top=(*top)->next;
remove->next=0;
return remove;
}
my confusion:
NODE:
typedef struct node {
int value;
struct node *next;
} NODE;
NODE * top my linked list holding values 1...10
NODE * holder is another pointer pointing to the 5th and 4th node of the linked list, respectively
switchnodes(&holder); holder pointing to the 5th node. The 6th node gets lost
switchnodes(&(holder->next));holder pointing the 4th node. 5th and 6th nodes successfully swapped.
why does that happen?
and how do I write this function so I don't have to pass pointer->next? I can't do that in every instance, like if its the top node I need to swap.

That's the way your list works: You can only swap nodes via next pointers; holder is a pointer outside the list. It may get updated, but the list won't know.
Say holder points to the 4th node. You swap it, it now points to the new 4th node, the former 5th node. But what's important: The next pointer of the list's third node still points to the 4th node - 4th before swapping that is.
You can make your list two-way by having a haed and a tail and an additional prev pointer for each node. Then you can use that information to update the swapped nodes' neighbours, if any.

You have to update first's "next" at switchnodes function. Here is a working function:
void switchnodes(NODE **A)
{
if((*A)->next)
{
NODE *first = pop(A);
NODE *second = pop(A);
push(A,first);
first->next = second->next; //the missing line
push(A,second);
}
}

Related

Sentinel Node in a C Linked List

I'm trying to learn more about linked lists in C and I recently stumbled upon the Sentinel Node concept, but I can't wrap my head around it. According to the slides I have, the sentinel node should be the first thing on the list when it's created and the last when other nodes are added. There should be a pointer to permanently point to the Sentinel Node.
All those stuff confuse me and I would love some help with the implementation.
/*this is a simple LL implementation*/
#include <stdio.h>
#include <stdlib.h>
struct List
{
int data;
struct List *next;
};
void ListInsert(int new_data)
{
struct List *p;
p = (struct List *)malloc(sizeof(struct List));
p->data = new_data;
p->next = (head);
head = p;
}
void printList(struct List *q)
{
q = head;
while (q != NULL)
{
printf("%d ", q->data);
q = q->next;
}
printf("\n");
}
int main()
{
ListInsert(5);
ListInsert(7);
ListInsert(6);
ListInsert(4);
ListInsert(2);
printList(head);
return 0;
}
Now, if I want to create the sentinel node, how should I proceed?
According to the slides i have, the sentinel node should be the first
thing on the list when its created and the last when other nodes are
added.There should be a pointer to permanently point to the Sentinel
Node.
Let's start with the most important point: the purpose of a sentinel node, which is to mark the end of the list. There will not be real data associated with a sentinel node, so a list containing only a sentinel node is logically empty.
A few things follow from that, including:
the identity of the sentinel node is a property of the whole list, not of any (other) particular node
list manipulation algorithms need to be written differently for linked lists whose ends are marked by a sentinel than for those whose ends are marked by some other means.
each list need a place to store the sentinel's identity
a list that is expected to have a sentinel is invalid if it does not have one
There are many ways to implement the details, all with their own advantages and disadvantages.
Personally, I would be inclined (in the non-sentinel case, too) to have a structure to represent an overall list, separate from the structure used to represent a list node. A pointer to the list's head node would be a member of this structure, and in the sentinel-terminated-list case, so would be a pointer to the sentinel node. When you create a new list, you create a sentinel node for it, too; initially, the list's head and sentinel pointers will both point to that node. The head pointer may be changed, but the sentinel pointer must not be. When you append to the list, the appended node gets placed just before the sentinel. It is an error to try to delete the sentinel from the list.
It is to your advantage to write the code for this yourself.
Create it. You said "There should be a pointer to permanently point to the Sentinel Node", so create the pointer. Then use the pointer as the terminator of the list instead of NULL.
Sentinel node - Wikipedia
/*this is a simple LL implementation*/
#include <stdio.h>
#include <stdlib.h>
struct List
{
int data;
struct List *next;
};
struct List sentinel_node_instance;
/* a pointer to permanently point to the Sentinel Node */
struct List* const SENTINEL_NODE = &sentinel_node_instance;
/* the sentinel node should be the first thing on the list when it's created */
struct List* head = SENTINEL_NODE;
void ListInsert(int new_data)
{
struct List *p;
p = (struct List *)malloc(sizeof(struct List));
p->data = new_data;
p->next = (head);
head = p;
}
void printList(void)
{
struct List* q = head;
while (q != SENTINEL_NODE)
{
printf("%d ", q->data);
q = q->next;
}
printf("\n");
}
int main()
{
ListInsert(5);
ListInsert(7);
ListInsert(6);
ListInsert(4);
ListInsert(2);
printList();
return 0;
}
Another variation of a sentinel node is for a circular doubly linked list, where it is both a head node and a sentinel node. Visual Studio implements std::list in this manner.
head.next = pointer to first node or to head if empty list
head.prev = pointer to last node or to head if empty list
first.prev = pointer to head node
last.next = pointer to head node

How to dequeue a linked list in c if the element to be returned is not of primitive type?

I have this data structure:
typedef struct task
{
void (*function)(void *p);
void *data; // in my case, this is a struct with two integers
struct task *next;
}Task;
I want to have a dequeue function that returns the first element of type Task:
struct task* dequeue()
{
if (!head) {
return NULL;
}
Task *taskToReturn = head;
/********************
* PROBLEM'S HERE
********************/
head = head->next;
return taskToReturn;
}
Now, the problem is straightforward. I can't assign head to taskToReturn for the simple reason that I am changing the value pointed by head right after. How can I return an element that holds a struct and a function pointer and dequeue it?
Is it at all possible to get the element with a call like that?
Task *taskToDo = dequeue();
What you're doing to return the node you want is correct. The error here is that you're freeing the current head of the list. Stepping through the code:
Task *taskToReturn = head;
Here you're saving the current head in taskToReturn.
head = head->next;
Here you're repointing head to the second node in the list. Now head no longer points to the same node that taskToReturn points to.
free(head);
By doing this, you've lost you link to the rest of the list. Get rid of this line and you should be fine.

Reverse the pointers in a linked list

Hello guys could you please help me in writing a procedure to reverse the pointers in a linked list . for example A->B->C->D would become A<-B<-C<-D without using extra linked list .
Edit:
------ okay guys so i have been looking for solution for this problem here is the code in case u want it :
void reverse_list(){
struct node *next, *current,*previous;
previous = NULL;
current =head;
while(current != NULL){
next = current->next;
current->next = previous;
previous=current;
current = next;
}
head = previous;
}
You could think of the list as a stack. Then you could easily reverse such a list by "popping" the nodes and "pushing" them into a new list.
The above could be done both destructively (destroying the old list) and non-destructively (creating the new list as a reversed copy of the original list).
As you didn't mention if you are implementing the linked list yourself or not.
So firstly I am assuming that you are doing it by yourself. So following is an implementation of linked list and again its pointers are reversed to make the link list reverse. You can take an idea from it.
#include<stdio.h>
#include<stdlib.h>//for using malloc
struct Node//Defining a structure for linked list's node
{
int info;//assuming it is an integer linked list
struct Node *link;//this pointer links a node to it's immediate neighbor node
};
struct Node *head=NULL,*temp;//some initializations and declarations
void insertion(int data)//To insert elements to linked list
{
struct Node *ptr;
ptr=malloc(sizeof(*ptr));//creating a new node for the newcomer
ptr->info=data;//taking the given integer value for the node to hold
//initializing with null as the current node may be the last node and
//if it is then it will point nobody
//...but if it is not when a new node comes in the future it will eventually be
//replaced to point the newcomer
ptr->link=NULL;
if(head==NULL)//head still null means we are creating the first node
{ //handling the head separately as it has no parent node
head=ptr;
temp=ptr;//copying the current node's pointer to temp such that we can
//find it as a parent of next node
}
else//for the rest of the nodes' creation
{
//as temp is the pointer to the previous node, so previous node is linking
//to its next node, i.e, the current node
temp->link=ptr;
//updating the temp to point the current node such that it can act as a parent node
//when the next node comes
temp=ptr;
}
}
void reversePointers()
{
struct Node *trav,*from=NULL,*temp;
for(trav=head;;)
{
if(trav->link==NULL)//if we have reached to the end
{
head=trav;//then the reverse linked list's head should point to the last element
trav->link=from;//and making the second last node as it's next node
break;
}
temp=trav;//saving current node pointer to update the "from" pointer
trav=trav->link;//advancing current node pointer to forward
temp->link=from;//making the current node to point to it's previous node
from=temp;//saving current node's pointer which will be used in next iteration
}
}
void traverse()//to traverse the nodes
{
struct Node *ptr=head;
while(ptr!=NULL)
{
printf("%d ",ptr->info);
ptr=ptr->link;
}
printf("\n");
}
int main(void)
{
int i,n,t;
printf("Enter Number of elements: ");
scanf("%d",&n);
printf("Enter Elements: ");
for(i=0;i<n;i++)
{
scanf("%d",&t);
insertion(t);
}
printf("Before reversing the pointers the elements are: ");
traverse();
//let's reverse the pointers to make the list to go backward
reversePointers();
printf("After reversing the pointers the elements are: ");
traverse();
}
Secondly if you are using STL list then the approach is quite straightforward. Just use,
your_list_name.reverse()
Again if you want to reverse the STL list just for iteration purpose then there is no need to actually reverse it. Instead you can use reverse iterator as following (say for an integer list):
for(list<int>::reverse_iterator it=your_list_name.rbegin();it!=your_list_name.rend();it++)
{
//do whatever you want
}

How 'memory efficient doubly linked list' works?

In Data Structures and Algorithms Made Easy, struct of memory efficient memory list given as follows,
struct LinkNode
{
int data;
struct LinkNode* ptrdiff;
}
In ptrdiff, there will be xoring of previous and next node is done. For example, previous node have address 100 and next node address is 500.
So, in ptrdiff address will be 400. Now how it is possible to move to next or previous node (as we do in doubly link list), just by knowing xoring of their addresses?
Am I missing any step here?
The first node has no previous node, and the last node has no next node ... so think of the address of the node before the first and of the node after the last as 0. That's enough to start a traversal, and as you traverse you always have the address of the preceding node in hand so you can determine the address of the succeeding node. Here's an example of traversing such a list and printing the data ... pass the address of either the first or last node to printxorlist and it will print it either forwards or backwards:
void printxorlist(struct LinkNode* node)
{
struct LinkNode* prev = NULL;
while (node)
{
printf("%d\n", node->data);
struct LinkNode* next = (struct LinkNode*)((intptr_t)node->ptrdiff ^ (intptr_t)prev);
prev = node;
node = next;
}
}
Note that we have to cast node->ptrdiff because it doesn't really have the right type. Better would be to declare it correctly:
struct LinkNode
{
int data;
intptr_t ptrdiff;
}
then
void printxorlist(struct LinkNode* node)
{
struct LinkNode* prev = NULL;
while (node)
{
printf("%d\n", node->data);
struct LinkNode* next = (struct LinkNode*)(node->ptrdiff ^ (intptr_t)prev);
prev = node;
node = next;
}
}
In this type of linked list, you can not traverse from the address of any arbitrary node. Because you need some extra information either about predecessor address or successor address. But traversing from the first node(predecessor address =0 , since not any predecessor) or last node(successor address=0, since not any successor) is possible.

What more does the code need to delete a node from a linked list successfully?

I want to delete a given node from a linked list by the node's index number (serial number). So what I tried to do in my function is that, first I have taken the user input of the index number. Then I used two node type pointers temp and current. I started traversing the list with current and when the index number of the node matches with the user input, I tried to delete the node. So far it is correct. I am facing problem with the deletion logic. Here is the code I tried:
void delete_node(struct node **start,int index_no)
{
int counter=0;
struct node *temp, *current;
temp=(struct node *)malloc(sizeof(struct node));
current=(struct node *)malloc(sizeof(struct node));
current=*start;
while(current->next!=NULL)
{
counter++;
if(counter==index_no)
{
temp= current->next;
free(current);
/*I guess some code is missing here. Help me finding the logic.*/
}
else
{
printf("\n The index number is invalid!!");
}
}
}
The commented portion lacks the deletion logic.
Also, I have a feeling that this code is not space and time-efficient. If it is so, please suggest to a way to make it more compact.
Why are you allocating two nodes in the delete function, then leaking their memory? It seems they should be initialized to start or one of its successors.
You also need to update the next pointer in the previous element and potentially also the start (head) of the list if the removed element was the first (ie. index_no == 1).
You also have an off-by-one error where the final node can never be deleted, because only a node with a ->next pointer will be considered for deletion.
Suggested reading: A Tutorial on Pointers and Arrays in C.
Deleting from a linked list is actually:
find the pointer that points to us
(if found) make it point to our .next pointer instead
delete our node.
In order to change the pointer that points to us, we need a pointer to it: a pointer to pointer. Luckily the first argument already is a pointer to pointer, it presumably points to the head pointer that points to the first list item.
struct node
{
struct node *next;
int num;
} ;
void delete(struct node **pp, int num) {
struct node *del;
int counter;
for (counter=0; *pp; pp= &(*pp)->next) {
if(counter++ == num) break;
}
if (!*pp) { printf("Couldn't find the node(%d)\n", num); return; }
/* if we get here, *pp points to the pointer that points to our current node */
del = *pp;
*pp = del->next;
free(del);
}

Resources