How to add a node in a specific location? - c

I have been working with a doubly linked list. Everything works OK with the exemption of the function that should add a copy of 'who' before 'whereX' [see code bellow]. Why is the function not working?
void addNodeAt(Node *whereX, Node *who)
{
//copy
Node *temp = (Node*)malloc(sizeof(Node));
temp->count = who->count;
strcpy(temp->word,who->word);
temp->before = whereX->before;
temp->after = whereX;
//paste
if(whereX->after == who)
whereX->after = who->after;
whereX->before = temp;
}
EDIT:
In response to user326404 who said:
'Note: Your function does suffer a flaw that prevents it from inserting who as the new head of the list. It will insert, but you never return the new head node so the list is lost.'
what if I have a Node *head as a global variable. How can I reasign the head without returning it?

You are not letting the existing links know about the newly created temp node. Add the following code to the end of the function to let the preceding portion of the chain point to the newly created node.
if (whereX->before != NULL)
whereX->before->after = temp;
Note: Your function does suffer a flaw that prevents it from inserting who as the new head of the list. It will insert, but you never return the new head node so the list is lost.

Let's say you have this list:
[Node1] <-> [WhereX] <-> [Node2]
From these assignments:
Node *temp = (Node*)malloc(sizeof(Node));
temp->count = who->count;
strcpy(temp->word,who->word);
temp->before = whereX->before;
temp->after = whereX;
and from this:
whereX->before = temp;
you will have:
[Node1] <- [temp] <-> [WhereX] <-> [Node2]
| ^
----------------------
but Node1's after pointer is still looking at WhereX, so
you should also add this assignment:
whereX->before->after = temp;

What you are doing needs some changes. You have correctly allocated memory to duplicate.
But problem statement is not very clear.
Assuming you want to add a node before whereX, you have to do the following:
Point "after" pointer of temp to whereX
Point "before" pointer of temp to "before" pointer of whereX
Point "before->after" pointer of whereX to temp
Point "before" pointer of whereX to temp
Hope this helps.
EDIT:
Also do the appropriate NULL checks

Related

Linked lists and pointers confusion

I'm working on my final project and I was introduced to linked lists, which I must use.
I'm incredibly frustrated after trying to understand how the code works. The concept to me makes complete sense. The code i'm given as an example though, doesn't.
typedef struct node_s {
char name[20];
int age;
struct node_s *listp;
} node;
while (!feof(inp)) {
temp = (node *)malloc(sizeof(node)); // creation of memory
fscanf(inp, "%s%d", temp->name, &temp->age);
if (head == NULL)
head = temp; // setting the head of the list
else {
tail->listp = temp; // else connecting to previous element
}
tail = temp; // updating the current element
tail->listp = NULL; // setting pointer to null.
}
I'm confused at how tail->listp will point to the second element, when each time it's set to be NULL. To further illustrate my confusion, in the else statement tail->listp will point to the new element, which is understandable.
But at the end we point tail->listp to NULL which just disregard the else statement. Yet the code works just fine, and here I am, extremely confused.
You're missing the statement before, which is
tail = temp; // updating the current element
In a loop, you create a new element temp, and link it onto the list. If it's the first element, you start the list by setting it to both the head and the tail, essentially. If it's not the first element, you link it onto the end of the list.
tail->listp = temp;
Then, you set tail=temp to update the pointer to the end of the list, and make sure that the element at the end of the list is pointing to null
tail->listp = NULL;
You could also do
temp->listp = NULL;
tail=temp;
which would be equivalent, if my eyes don't fail me.

Changing nodes in linked list

This is somewhat mind-boggling
i will try to explain my doubt.
Check this function for example:
void snoc(Lint *l, int val){
Lint i, new;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
i=(*l);
while(i->next!=NULL){
i=i->next;
}
i->next = new;
}
I understand the concept behind and i have no trouble working with lists, taking in consideration that i can't iterate through the list using the list initial pointer itself (if i do this, i would lose the initial pointer right)
The thing is, making i=(*l) and afterwards iterating through the list using i=i->next, is making the i variable becoming in constant change.
In this particular example, the original list will not change until i find the end of the linked list, and then i make an attribution and voilá! I insert an element at the end.
My doubt is, if by changing the i, and making i->next = new at the end, wouldn't that mean that everytime i make i=i->next, change ALL the nodes in the original list?
Another example would be init:
void init (Lint *l){
Lint i, prev;
i=(*l);
prev=NULL;
while(i!=NULL){
if( (i->next)->next==NULL){
i->next = NULL;
}
i=i->next;
}
}
if i do this, the last element will be removed, by changing the i->next to NULL, at the right moment. But before that, i've been making changes to the i itself again, by telling i=i->next
If i were to make this change to the (*l) itself (by doing (*l)=(*l)->next) i would be ruining the original list .
I really hope you guys can understand my doubt.
Yes, we do understand your confusion, and it comes from not working out the list pointers on a piece of paper so you can visualize what is taking place. Always use a diagram when you are working node link issues. For example in your case with your singly linked-list, current node called i (dubious choice of name) and your new node called new a helpful diagram would be:
Singly Linked-List (non-circular)
Tail Current Head
(list start) i new
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->NULL
+------------+ +------------+ +------------+
Now, I bet you can tell what:
changing i, and making i->next = new at the end
would do. This isn't a dig or meant to be condescending, it is really the way you need to work out linked-list issues until you have done it enough you can visualize the pointer wiring in your head. This is even more important when you get to circular or doubly-linked list insertions and deletions. No matter what the problem, if you just write it down and label all the connections that are being made or broken, you can then code it cleanly in your editor.
with some minors modifications your code is like this
void snoc(Lint *l, int val)
{
Lint i, new;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
i = *l;
if(!(*l))
{
*l = new;
return;
}
while(i->next) i = i->next; // (1)
i->next = new; // (2)
}
and, this is its explanation:
In (1) we walk throught the linked list until its end. We know we are at the end because i->next (which point after each loop step to the next nodo item) is null so in that case, we make i->next point to the newly created nodo item in (2). But l never changed during the function, l is always pointing to the begining of our linked list so the purpose of this function is to add a new element at the end without changing the value of l.
but also we can initialize our linked list with this function...for example:
Lint l = NULL;
snoc(&l, 10); // l will be initialized with a new nodo item with 10 as the value its value member
(0) checks if l is null in that case we make *l point to the newly allocated nodo item and return...so initialization done.
I add another way for the code above
void snoc(Lint *l, int val)
{
Lint now, new, previous;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
if(!(*l)) // (0)
{
*l = new;
return;
}
for(now = *l; now; now = now->next)previous = now;
previous->next = new;
}
I am not sure I understand your question, but why don't you simply copy the pointer? You can keep a pointer to the initial element and use a second one to traverse though it.

understanding linked list-like structure in c

I'm having trouble understanding a piece of C code that represents a linked list structure. The skeleton of the struct looks like this:
struct r{
r *next;
r **prev;
data *d;
}
struct r *rlist;
rlist can be filled by calling the following function: (skeleton only)
r* rcreate(data *d){
struct r *a = xmalloc(sizeof(*r))
a->d = d;
a->next = rlist;
a->prev = &rlist;
if (rlist)
rlist->prev = &a->next;
rlist = a;
return a;
}
How do I go about using this data structure? e.g. how to traverse rlist ?
Edit: here is the function for deleting a node in the linked list
void rdestroy(struct r *a){
if (a->next){
a->next->prev = a->prev;
}
*a->prev = a->next;
destroy(a->d); /* destroy is defined elsewhere */
}
Double prev pointer seems to allow traversing list in one direction only, while allowing easy deletion (because even though you can't access the previous element (easily), you can access the next pointer of previous element, and set it to new correct value when deleting a node.
Without seeing other related functions, it's hard to see why it is done this way. I've not seen this done, and can't immediately think of any really useful benefit.
I think this allows having simpler node deletion code, because node does not need to care if it first or not, because node's prev pointer will always have non-NULL value to a pointer it needs to modify when deleting itself. And same simplicity for insertion before a current node. If these operations are what dominate the use pattern, then this could be seen as minor optimization, I suppose, especially in older CPUs where branches might have been much more expensive.
How to traverse list
This was the question, right? You can only traverse it forward, in a very simple manner, here's a for loop to traverse entire list:
struct r *node;
for (node = rlist ; node ; node = node->next) {
// assert that prev points to pointer, which should point to this node
assert(*(node->prev) == node);
// use node
printf("node at %p with data at %p\n", node, node->d);
}
Example insertion function
This example insertion function demonstrates how insertion before a node needs no branches (untested):
struct r *rinsert(struct r *nextnode, data *d) {
// create and initialize new node
struct r *newnode = xmalloc(sizeof(struct r));
newnode->d = d;
newnode->next = nextnode;
newnode->prev = nextnode->prev;
// set next pointer of preceding node (or rlist) to point to newnode
*(newnode->prev) = newnode;
// set prev pointer of nextnode to point to next pointer of newnode
nextnode->prev = &(newnode->next);
return newnode;
}
There's no good reason to have r ** next in that structure. It's for a double linked list.
So if this thing is created you have it assigned
thisList = rcreate("my data")
now you could start with traversing it
while (thisList->next)
thisList = thisList->next.
...
Your code has many syntactical errors in it, probably because (as you say) it is a "skeleton," so it is hard to parse what the author (whether it was you or someone else) actually intended this code to do.
A simple (doubly) linked list structure looks like this:
struct node {
struct node *next, *prev; // pointers to the adjacent list entries
int data; // use whatever datatype you want
};
struct node *list = NULL; // the list starts empty
void add_entry(int new_data) {
struct node *new_entry = malloc(sizeof(struct node));
// note that in the above line you need sizeof the whole struct, not a pointer
new_entry->data = new_data;
new_entry->next = list; // will be added to the beginning of the list
new_entry->prev = NULL; // no entries currently front of this one
// in general a NULL pointer denotes an end (front or back) of the list
list->prev = new_entry;
list = new_entry; // now list points to this entry
// also, this entry's "next" pointer points to what used to
// be the start of the list
}
Edit: I'll say that if you want us to help you understand some code that is part of a larger program, that you did not write and can't modify, then please post the relevant code in a format that is at least syntactical. As others have said, for example, the use of prev in the code you posted is indecipherable, and it isn't clear (because there are other similarly confusing syntactical problems) whether that was in the original code or whether it is an error introduced in transcription.
Yang, I am not sure how comfortable you are with pointers in general. I suggest taking a look at few other linked-list implementations, it might just do the trick.
Take at look at this Generic Linked List Implementation.

Adding nodes to a global linked-list

I am attempting to construct my first linked list, and having read a basic introduction, have done the following. Firstly, declare a linked list node as:
struct errorNode {
uint8 error;
struct errorNode* next;
};
Secondly, define the first node globally as:
struct errorNode errorList = {0, NULL};
This has been done to allow each of the libraries that make up my current project to insert errors into a common list. The function to do this is:
void errorListWrite(uint8 error) {
struct errorNode* newNode = malloc(sizeof(struct errorNode));
newNode->error = error;
newNode->next = &errorList;
errorList = *newNode;
}
Whilst this compiles without error, it does not function as expected. I thnk the problem is with the last two statements of the list write function, but I am unsure. A hint as to what I am doing wrong would be most appreciated.
The problem is that you create a circular list.
newNode->next = &errorList;
So newNode links to the global node.
errorList = *newNode;
This is equivalent to errorList.error = newNode->error; errorList.next = newNode->next;.
So now errorList links to the global node. Oops.
What you could do instead, is insert the new node after the global node in the list:
newNode->next = errorList.next;
errorList.next = newNode;
This is assuming that you want a global node at all. If you don't, then you could start with struct errorNode *errorList = 0;, and add a new node like this:
newNode->next = errorList;
errorList = newNode;
When you come to use the list, your list-traversal may look a little different. With a global pointer-to-node you'll start with a pointer to the first node, that you must check for null before using. With a global node you'd start with a node that definitely exists, but whose next pointer might be null.
Well, the problem is with the last line: you are just overwriting the data in in the old error node!
What you probably need is to have the head (pointer to the first node) globally accessible, not the first node itself. This way you don't need a fake entry in your list.
(Be warned that your code is not thread-safe.)
Code:
errorNode* pGlobalErrorList = NULL;
// in errorListWrite
newNode->next = pGlobalErrorList;
pGlobalErrorList = newNode;
Your head (errorList) should be a pointer and should be initialized to NULL unless you have a need for the initial entry of a node with a value of 0:
struct errorNode* errorList = NULL;
Then your function needs to reassign errorList properly.
void errorListWrite(uint8 error) {
struct errorNode* newNode = malloc(sizeof(struct errorNode));
newNode->error = error;
newNode->next = errorList;
errorList = newNode;
}
This is all assuming your new node will be the new head of the list, and not the new tail.
errorList should be a pointer to first node (not the first node)
also you need to know what is the last node this will be modified
the head of list will not be modified, it will be used only when you want to travel from the beginning of list.

Copy a linked list

typedef struct Node
{
int data;
Node *next;
Node *other;
};
Node *pHead;
pHead is a singly linked list. The next field points to the next element in the list. The other field may point to any other element (could be one of the previous nodes or one of the nodes ahead) in the list or NULL.
How does one write a copy function that duplicates the linked list and its connectivity? None of the elements (next and other) in the new list should point to any element in the old list.
Create a new node for every node in the old list, copy the corresponding data and make the next pointer of the nodes in the new list point to their successor in the new list, forgetting the other pointer for time being. At the time of creating a new node remember the mapping of node address something like:
Old_list New_list
-------------------
0x123 0x345 [ addresses of the first node]
0xabc 0xdef [ addresses of the second node]
...
In the second pass pass for every node in the new list consider its other pointer and find its corresponding node in the new list from the map and use it as the other pointer of this node (node in the new list).
Came across this. Hope it helps!
Citing one solution from this link, below.
1) Create the copy of 1 and insert it between 1 & 2, create the copy of 2 and insert it between 2 & 3.. Continue in this fashion, add the copy of N to Nth node
2) Now copy the arbitrary link in this fashion
if original->arbitrary is not NULL
original->next->arbitrary = original->arbitrary->next; /*TRAVERSE TWO NODES*/
else
original->next->arbitrary=NULL;
This works because original->next is nothing but copy of original and Original->arbitrary->next is nothing but copy of arbitrary.
3) Now restore the original and copy linked lists in this fashion in a single loop.
original->next = original->next->next;
copy->next = copy->next->next;
4) Make sure that last element of original->next is NULL.
Sample code, Time Complexity O(N), Space Complexity O(1)
pNode copy_list(pNode head) {
// pre-condition: node->other either points into the list or NULL
if (!head) return NULL;
pNode node = head, copied = NULL, cnode = NULL;
for ( ; node; node = node->next->next) {
// make copy
cnode = newnode(node->next, node->data);
cnode->other = node->other;
if (node == head)
copied = cnode;
// insert the copy between originals
node->next = cnode;
// node -> cnode -> (orig)node->next
}
for (node = head; node && node->next;
node = node->next->next /* only original nodes */)
if (node->other)
node->next->other = node->other->next;
else
node->next->other = NULL;
// restore lists
node = head; cnode = copied;
for ( ; cnode && cnode->next; node = node->next, cnode = cnode->next) {
node->next = node->next->next;
cnode->next = cnode->next->next;
}
node->next = NULL;
return copied;
}
Complete program is at http://gist.github.com/349630
I like the solution of Codaddict, but this would be my answer:
iterate over the linked list.
a. store the data in an array (position i for the i'th node of course)
b. replace data with i to create an id (this way you'll definitely know which node you are talking about)
create the 2nd linked list the size of the first (ignore the other pointer for now)
*. maybe use a temporary array to find each node quickly
iterate over the first linked list.
a. find out which id other points to (which is in that nodes data)
b. recreate this link in the 2nd linked list (the temporary array could really help here)
iterate over both linked list simultaneously and replace the ids in data with the stored data
Of course you could collapse some processing and iterating here. But this would roughly be what I would do/think of.

Resources