swap elements in a linked list without access to it? - c

if i have a reference to an element in a linked list, how do i swap it with the next element, in c
here's a try,
Node* nRoot, *temp=pNode->next;
nRoot=pNode;
do{
nRoot->next = temp->next;
if(nRoot==pNode) pNode=temp;
temp->next = nRoot;
nRoot=nRoot->next;
}while(nRoot!=NULL)||temp!=NULL);
but it does not work

You can only do this if it double linked list. You need the previous pointer so that you can point it's next to the current's next.
However if you have these then you an do something like this:
Node* next = curr->next;
Nide* prev = curr->prev;
curr->prev = next;
curr->next = next->next;
curr->next->prev = curr;
next->prev = prev;
next->prev->next = next;
next->next = curr;
And the 2 are swapped.
Edit: Of course you can do this with a singly linked list but you do need to know the previous node so that you fix up its next pointer to point to the current's next.

If you have a reference to A and A->next is B, you can do this. I'm assuming they hold a Data* pointer, replace with whatever the data is. Don't actually swap the nodes, just swap the data in the nodes.
void push_forward(Node* curr)
{
Data* currData = curr->data;
curr->data = curr->next->data;
curr->next->data = currData;
}
For the record, I am not a C guy so this might be correct only in algorithm, but not in implementation. I welcome edits, fixes, suggestions, and constructive comments!

If there are no external pointers to the elements that you wish to swap, then you can just swap the data within the list nodes, rather than the nodes themselves, as pointed out in other answers.
If you have external pointers to the list nodes, then you should probably not mess with the node content, unless the rest of your program is find with node contents changing from under its feet.
You will have to swap the nodes, which means that you need to have a pointer to the node that precedes the ones that you need to swap. If you only have the head of the list, then the swap function could be something along these lines:
void swap(Node **list, Node *first) {
Node *i = *list;
Node *p = NULL;
while (i != NULL) {
if (i == first) {
Node *n = i->next;
/* No next node to swap with */
if (n == NULL)
break;
if (p != NULL) {
p->next = n;
} else {
*list = n;
}
i->next = n->next;
n->next = i;
break;
}
p = i;
i = i->next;
}
}

Related

Reverse fuction for singly linked list isn't working as it should

we've given a task to reverse a singly linked list and for some reason i struggling with it
its reversing as it should ,but the head that should be the tail just disappears and i can't figure why, even after debugging
'''
void Reverse(struct node *head) {
struct node *last = NULL;
struct node *current = NULL;
struct node *temp = NULL;
current = head;
while (current->next != NULL) { //getting ptr to last item of the list
current = current->next;
last = current;
};
current = head; //resseting the current ptr back to the head of the list
while (current->next->next != NULL) { //getting the current ptr to one before the tail item
current = current->next;
};
temp = last;
while (last != head) {
if (current->next == last) {
last->next = current;
last = current;
current = head;
if (last == head) {
head->next = NULL;;
head->data = temp->data;
head->next = temp->next;
break;
};
};
};
};
'''
I can't completely follow the logic in your code. You find the last and the second last element, and I will assume that head is some dummy element that you always have (because otherwise, not checking if it is NULL is a problem). After that, I am not sure what happens. You "flip" the last two links if you are looking at the head you update it? (You don't need to set head->next to NULL before you update it two lines later; that doesn't do anything).
Did you want to move current from the head and down to the one before last somewhere in the loop? I think that would work, but you would get a quadratic time algorithm.
If we assume that head is a dummy, so it doesn't have any elements to worry about, and we just want its next pointer to point to the reversed links, you should be able to do something like this:
void reverse(struct node *head)
{
struct node *next = head->next;
head->next = 0;
while (next) {
struct node *next_next = next->next;
next->next = head->next;
head->next = next;
next = next_next;
}
}
In the while-loop you can think of the code as pushing next to the front of the list pointed to by head->next and popping it off the current list (by setting next to next_next. When you reach the end of the list, head->next points to all the links, in reversed order. (I haven't tested the code, but I belive it should work).
If head is not a dummy node, you have to handle the special case that it is NULL, and you have to move its value. It makes things trickier if you have to do the latter, especially if you want to use the list generically, where the user is allowed to allocate links, and you might not know what data is in them (beyond that they have a link embedded in them). I would go for having a dummy link if you can, it makes everything simpler, not just reversal.
Of course, with doubly-linked lists it gets simpler still:
#define swap_p(x,y) \
do { struct node *tmp = x; x = y; y = tmp; } while(0)
void reverse(node *dummy)
{
struct link *p = dummy;
do {
swap_p(p->prev, p->next);
p = p->prev;
} while (p != dummy);
}
but that might not be what you want.
Don't know if that helps, but I hope it does a little at least.

How to shift a linked list's data? (in C)

My question is simple and answers too rare. I know how to add or remove a node but how do you copy one previous node's data to the following node? Basically with an array the easiest way to shift it is to copy to the last element the previous element and move up the array like so:
for (i = number_of_elements ; i > 0; i--)
tab[i] = tab[i-1];
Otherwise you would copy each element to the next and have the same data for each element which we don't want.
Then I can assign to tab[0] a new value.
But how to do that with a linked list? I know how to add a node to the beginning of the list:
struct node *node (struct node *head, int data)
{
struct node *new_node = malloc(sizeof(struct node));
new_node->data = data;
new_node->next = head;
// new_node->prev = ??
return new_node;
}
which I assign to my list pointer so that it adds to the left. But I can't go up a linked list. Since the pointer next leads to the next node. Do I have to add a prev pointer to each node? But to what should it point? Thank you for helping in any way or for your rebuke because I just can't think properly.
edit: My idea then is to do simply as follows:
for (current = head; current!= NULL; current=current -> next) ;
and from there:
for( ; current!= head; current = current -> prev)
current ->data = current -> prev -> data;
return head;
Something like this?
void Shift(node* Head) {
type PrevData = Head->Data;
Head = Head->Next;
while (Head) {
type Temp = Head->Data;
Head->Data = PrevData;
PrevData = Temp;
Head = Head->Next;
}
}

Inserting node into sorted linked list in C

I need to insert a node into a sorted linked list. The list has a dummy node.
void add(Node **nodeArray, int setNumber) {
char userString[5];
Node *head = nodeArray[setNumber]; /* head pointer to first element of array (dummy) */
Node *newNode = malloc(sizeof(Node)); /* new node to be added to array */
Node *tmp = head;
printf("Please enter some data: ");
scanf("%s", userString);
strncpy(newNode->data, userString, DATA_SIZE); /* copies string entered by the user to data field of new node */
newNode->next = NULL; /* initializes next field of new node to NULL */
while (tmp->next)
tmp = tmp->next; /* points head to next element in list */
tmp->next = newNode; /* adds element to list */
}
This inserts a node at the end of the list. I understand the logic of the added sort. You look ahead to the next node and if the new node is less than the next, you point the new node to the next node and the previous node to the new node. Can someone help me implement this in code. This is what I have so far, but does not work.
if (!tmp->next)
tmp->next = newNode;
else {
while (tmp->next) {
if (strcmpa((tmp->next)->data, newNode->data) < 0) {
newNode->next = tmp->next;
tmp->next = newNode;
} //else if (strcmpa((tmp->next)->data, newNode->data) > 0) {
//tmp->next = newNode;
//}
tmp = tmp->next;
}
}
Here is the compare function:
int strcmpa(char *s1, char *s2) {
while (*s1 && tolower(*s1) == tolower(*s2))
{
s1++;
s2++;
}
return tolower(*s1) - tolower(*s2);
}
You're almost there but tmp->next should be redirected to newNode itself, not to newNode->next. Actually, that's a no-operation, because at the time of that command, newNode->next is what tmp->next was and you're reassigning a value that's already there.
What you want is that tmp, having pointed to X, points to next instead, which then only points to X. So, formally,
X = tmp->next;
tmp->next = newNode;
newNode->next = X;
which can be condensed to
newNode->next = tmp->next; /* using the X where originally stored */
tmp->next = newNode; /* rewriting that memory has to wait till now */
Update: The above code links newNode after tmp (as I thought that was what you needed). But in the sorted list, you find the first tmp that needs to appear after your node, so you need to go before that. This brings two problems:
You need to modify what the item before tmp points to, because the new node will go there, so you need to keep one more variable,
sometimes you'll need to put the new node in the very beginning, which has no previous node.
On the plus side, the above also handles !tmp->next (insertion at the end) gracefully so you don't really need another branch for that case.
It will look something like
Node* head = (whatever);
Node* prev = NULL;
Node* tmp;
for(tmp = head; tmp && strcmpa(tmp->data, newNode->data) < 0; tmp = tmp->next) {
prev = tmp;
}
/* now tmp points to the first larger node or to NULL and prev is its preceding node.
* If there's none (if the head is already larger) then prev = NULL. */
if(prev == NULL) {
newNode->next = head;
head = newNode; /* Don't forget to update this in the array where you took head from! */
} else {
newNode->next = prev->next;
prev->next = newNode;
}
This works also if head was NULL and creates a linked list with a single entry.
This focused on the insertion. Regarding the rest of your code (originally posted as comments):
The program will fail if you overrun the userString buffer on the unrestricted %s scanf. Set a limit.
With a limit, you don't need the unsafe strncpy. Use a normal strcpy that guarantees it will null-terminate your string.
Your strcmpa looks fine. But do make sure tolower() does what you expect it to with an input of '\0'. This compares the strings correctly:
char toLower(char in) {
if(in >= 'A' && in <= 'Z')
return in + 'a' - 'A';
else
return in;
}

Pointer to struct incrementation

was implementing a singular linked list in C.
struct node
{
int data;
struct node *next;
};
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head,*track;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next=0;
if(head!=NULL)
head->next = curr;
head = curr;
}
curr = curr-10;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
As there are 10 elements in the list, so to make the pointer point to the first element, I tried decreasing curr (pointer to struct) by 10, but this got me half way through the list, the values printed were 5,6,7,8,9,10.
The size of the struct is 4, whereas the size of the pointer is 2, it seems the pointer is decreased by 2*10=20 bytes instead of 40, is this normal? (as I read that pointer increments/decrements according to the size of its type)
You cannot use pointer arithmetic on a linked list: the items are allocated separately (with malloc) and so they will not be necessarily adjacent in memory. That approach would only work with an array.
There are several problems.
First of all, the following insertion code isn't correct:
if(head!=NULL) head->next = curr;
head = curr;
Basically, the element pointed to by head is irrevocably lost.
Secondly, the behaviour of the following code is undefined:
curr = curr-10;
You cannot move across several malloc()ed blocks using pointer arithmetic.
Once you fix the insertion logic, it will become possible to traverse the list like so:
for (curr = head; curr != NULL; curr = curr->next) {
....
}
Your code curr = curr-10 will not bring you back to the head of the linklist.
As Viruzzo pointed out in a comment, you cannot use pointer arithmetic on elements of a linked list. As the word "linked" implies, there are only pointers linking the items together, they're not required to be located at adjacent addresses.
The pointer arithmetic will simply decrease the pointer by a fixed number of bytes, it will not follow pointers. Your list, being singly-linked, doesn't even have previous-element pointers to follow.
curr = curr-10; is wrong. It does not perform the operation that you think it does!
To print the contents of your linked list, you need to start from the head and go through each and every node until you hit NULL (assuming its not a circular list).
void display()
{
NODE * current = head;
if (current == NULL) {
printf("Empty list \n");
return;
}
while(current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return;
}
And to add new node in the front, you can use the following code snippet.
void addfront(int data)
{
NODE *newnode = NULL;
if ((newnode = malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("Couldn't allocate space for new element \n");
return;
}
if (head == NULL) {
// empty list
head = newnode;
tail = newnode;
} else {
newnode->next = head;
head = newnode;
}
return;
}
To add new node at the rear, you can use the following code snippet.
void addrear(int data)
{
NODE * newnode = NULL;
if ((newnode = (NODE *) malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("unalbe to allocate memory to the new element - %d \n", data);
return;
}
if (tail == NULL) {
assert(head == NULL && tail == NULL);
head = tail = newnode;
} else {
tail->next = newnode;
tail = newnode;
}
return;
}
All the above mentioned code snippet assumes, you have head and tail as global variables.
Hope this helps!

Linked Lists delete node at position N

EDIT: Figured out the problem. Also if you found this through google or another search engine here is where I went wrong and how to fix it.
My deleteNode() method was moving through the list properly with the correct temp and keeping the head untouched. Where I was going wrong was in what I was returning as the result of the method. I was returning either temp or newNode which is incorrect because it goes through the list until it finds defined position. Once it finds that defined position it it would reassign the ->next pointer to point to the next->next> pointer which is correct but again I was returning the wrong thing. Because we had moved through the list using temp/NewNode we lost the header and we were returning the position we found and whatever was still in the next positions of the list.
How we fix this is returning the head (which is what is passed into the method). The reason why this works is because we have to understand how LinkedLists work. The pointers of each node point to the next node. Ex. we have a linked list |A|| - |B|| - |C|| - |D|| - |E|| - |F||
If we want to delete Node C we move to node B using the temp pointer and then assign the B->next to temp->next->next Thus skipping over C node and assigning D node.
NOTE: (From what I know this does not actually free the memory of C node so it isn't best practice because you can cause memory leaks this way) You should use the free() method on the C node.
Here is the code I ended up using
struct node* DeleteNode(struct node* head, int pos) {
struct node* temp = head;
int length = LinkedListLength(temp);
int i;
if(pos <= 0 || pos > length){
printf("ERROR: Node does not exist!\n");
}else{
if(pos == 1){
head = head->next; //move from head (1st node) to second node
}else{
for(i = 1; i < pos-1; ++i){ //move through list
temp = temp->next;
}
temp->next = temp->next->next;
}
}
return head;
}
Hopefully that helps understand how I went out fixing it.
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
ORIGINAL POST
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
EDIT: Note: This is a homework assignment I have spent a few days (estimated 4 hours) programming it I am just stuck on this one part. You can view my attempt below
I've been able to insert and delete from begining/end however I can't seem to get my delete node at position N in linkedlist to work.
My psuedocode looks like this:
LinkedList: 1,3,5,7,9,23
Grab LinkedList
Create new struct node A = head
Move through linkedlist until
position
Assign node to node->next
return linkedlist
EXAMPLE INPUT
Node structure
int data;
struct node* next;
int values[] = {1,3,5,7,9,23};
struct node* llist = CreateList(values,6);
llist = DeleteNode(llist, 1);
llist = DeleteNode(llist, 5);
llist = DeleteNode(llist, 3);
Which should leave the llist with the values 3, 5, 9 once the code has been run However, It is replacing the first node with a 0
Actual Code:
struct node* DeleteNode(struct node* head, int pos) {
struct node* temp = head;
struct node* newNode = head;
int length;
int i;
printf("DeleteNode: position = %d \nBefore: ", pos);
PrintList(temp);
if(pos <= 0){ //node does NOT exist
printf("ERROR: Node does not exist!\n");
}else{ //node DOES exist
length = LinkedListLength(temp);
if(length < pos){ //if length < position Node does not exist
printf("ERROR: Node does not exist!\n");
}else{
if(pos == 0){
newNode = temp->next;
}else if(pos == 1){
newNode = temp->next;
}else{
for(i = 1; i < pos; i++){
printf("i = %d\n", i);
temp = temp->next;
newNode->next;
}
if(temp->next == NULL){
newNode = NULL;
}else{
newNode = temp->next;
}
}
printf("After: ");
PrintList(newNode);
printf("\n");
}
}
return newNode;
}
EDIT #2: Code typo
Thanks for any help in advance. From what I have concluded my problem is that I am not moving through the list properly but I am unsure as to why I am not.
In your code, you have the line
newNode->next;
in your for loop. That operation doesn't do anything.
You also have
newNode-> = NULL;
which is not valid C, and I have no idea how you got that to compile.
But really, don't use that loop. A linked list is one of the most basic recursive data structures. As a result, almost all algorithms manipulating them are most elegant as a recursive solution.
typedef struct node node_t;
node_t* delete_at_index(node_t* head, unsigned i)
{
node_t* next;
if(head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next) /* If i == 0, the first element needs to die. Do it. */
: (head->next = delete_at_index(next, i - 1), head); /* If it isn't the first element, we recursively check the rest. */
}
Removing a given node n from a singly-linked list can be boiled down to this operation:
Set the pointer that points to n to point instead to n->next.
You can break this down into two operations:
Find the pointer that points to n;
Set that pointer to n->next.
The complication arises because the pointer that points to n might either be the p->next field of the previous node in the list, or the head pointer (if n is the first node in the list).
Your code does not appear to be complete - it doesn't ever set the ->next field of any node to anything, so it's hard to say what's actually wrong.
// Remove list's node located at specified position.
// Arguments:
// head -- list's head
// pos -- index of a node to be removed (1-based!!!)
struct node* DeleteNode(struct node* head, int pos)
{
struct node* node;
struct node* prev;
int length;
int i;
printf("DeleteNode: position = %d \nBefore: ", pos);
PrintList(head);
// Check position's lower bound. Should be >= 1
if(pos <= 0) { //node does NOT exist
printf("ERROR: Node does not exist!\n");
return head;
}
// Seek to the specified node, and keep track of previous node.
// We need previous node to remove specified node from the list.
for(i=1, prev = 0, node = head; i < pos && node != 0; i++) {
prev = node;
node = node->next;
}
// Out of range
if(0 == node) {
printf("ERROR: Index out of bounds!\n");
return head;
}
// #node points to a list's node located at index pos
// #prev points to a previous node.
// Remove current node from the list.
if(0 == prev) {
head = node->next;
}
else {
prev->next = node->next;
}
free(node);
return head;
}
Your DeleteNode doesn't delete a node, it removes pos nodes from the front of the list. So you're trying to remove 9 items from a list that only contains 6, resulting of course in an empty list (NULL). Also, your code is overly complex and contains remnants of previous attempts. Please don't do that to yourself or to us; provide simple clean code and it will be easier to understand and to fix.
Figured out your for loop isn't reaching the desired position you wanted.
Better use equal to sign for the constraint it will work.
e.g.
for (i=1;i<=position-1;i++)
{
}

Resources