how to destroy a linked list in c? - c

i have this node :
typedef struct node {
DATA *dataa ;
struct node* next;
} *node_v;
with the asumption that i have already filled the linked list .. i want now to go over it and destroy it ..
i have made this function to destroy :
void destroyList(Node ptr) {
while(ptr) {
Node toDelete = ptr;
ptr = ptr->next;
free(toDelete);
}
}
it takes a node and free it . but my problem that each node i made the next points to NULL and the previous node points to the new node !
but the destroylist function does the opposite.. which means in order to deleate a node i call the function destroy list with the the last node i entered but then the toDeleate also points to it and the last node i enetred now points to the next node which in my case it is null , so i want to do the opposite.. any ideas of hiw i can do this !
like how can i make a destroy function that goes in the opposite direction !?

I call the function destroy list with the the last node I entered ... how can I make a destroy function that goes in the opposite direction?
With a singly-linked list, there is only one direction you can go, the direction in which the links are pointing. It sounds like the state of your list after building is something like:
pointer
|
V
firstVal -> secondVal -> thirdVal -> NULL
and you then call destroyList(pointer). That is not what you need for a singly-linked list. Such a list should maintain a head pointer to the start of the list, as follows:
pointer
|
V
firstVal -> secondVal -> thirdVal -> NULL
If you were to build your list like that, then your code for destroying the list would work just fine.
Since you haven't actually shown the code that builds the list (instead giving only a description of said list once built), that's most likely your problem.
In order to build the list correctly, you can use pseudo-code such as:
head = null
def append(head, tail, node):
node.next = null
if head == null:
head = node
tail = node
return
tail.next = node
tail = node

Related

What really is the head of a linked list

I have a question regarding linked lists and hash tables in C.
Is the so called head of the linked list supposed to be just a pointer to the first node or can the head be the first node?
void insert(int item)
{
//Making space for a new node
node *link = malloc(sizeof(node));
//Checking if valid
if (link == NULL)
{
return;
}
//Assigning the value of the node
link->value = item;
//Assigning the next to be the first element
link->next = first;
//Assigning first to be the current node
first = link;
}
Above code is from my insertion function of linked list. The "first" is assigned as node *first = NULL;
So the question here is that should I make a dedicated pointer that only holds the address of the first node or is this just fine. The code seems to work just fine.
And the same question sort of holds with hash tables. Should the array in hash table hold only the pointer to the first node or should the tables index slot hold the first node.
I hope my question is understandable. Feel free to ask if something doesn't make sense or need more of the linked list implementation I did.
Thanks in advance!

linked list undefined behavior

An abstract question: Say I have a singly-linked list of the nodes:
#node 1 #node 2
root->[data|next]->[data|next]->NULL
In C, root is declared:
struct Node *root = NULL;
where *root is the Node pointer 'holding' the address "NULL".
Now, lets say that I want to remove the last node in the linked list, the following code will allow the computer to do such action:
//pop: pop removes last/latter node in linked list and sets new last node to NULL
void pop(struct Node *root){
struct Node *last;
struct Node *current = root; //current point to same node as root
while(current->next != NULL){
if(current->next == NULL) {break;} //premature break in traversing of linked list; will stop at last node
last = current; //last points to same node as current
current = current->next; //move current to next node
}
last->next = NULL; //point second-to-last node to NULL, making it defacto last node in list
free(current); //free last node to heap
}//end pop
after calling pop and passing root to the function, the new linked list looks like this:
#node 1
root->[data|next]->NULL
If the program calls pop again, we should expect the linked list to look like this:
root->NULL
However, it does not! In the case of a linked list of integer elements in order, we will call pop until we observe strange behaviour:
List: 1 2 3
Call pop
List: 1 2
Call pop
List: 1
Call pop
List 1980765
The above is an example of undefined behavoir caused by a dangling pointer. Now the question is: How can the program avoid this behaviour and produce a side-effect that close to root->NULL from popping all nodes from the linked list until said list is empty?
First:
This condition can never ever be true:
if(current->next == NULL) {break;}
If it was true, we wouldn't reach that line but fall out of the while loop.
Second:
If you do not execute the body of the loop at least once, your pointer last keeps uninitialized. Hence
last->next = NULL;
sets a random memory location to NULL
Third:
When you try to remove the last remaining element, you need to free(root). But you cannot set root to NULL as it is passed by value.

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 and Deleting nodes from linked list

2 Questions:
I'm writing a function to prepend a node to a list. Currently I have it like this:
void addList( NODE_TYPE** head, NODE_TYPE** d_name )
{
(*d_name)->next = *head;
*head = *d_name;
}
and inside main(), I call it like this:
addList( &head, &node_3);
My question is, is there another way to do this with a function prototype such as:
void addList( NODE *head, NODE *node);
?
This was a class problem, and I don't understand how prepending can be done with the above function prototype since calling the function would only pass in the value of the address, the caller would be unable to see any changes made to the head nor the node.
I'm unsure if my deleteList function is right. I want it so that the temp points to where head (anchor) points to. Then the next_free points to the 2nd node linked with the head. Then I free the first node. Then repeat for the second, third and so on, until all of them are freed.
void deleteList( NODE_TYPE** head )
{
NODE_TYPE* temp = *head;
NODE_TYPE* next_free = NULL;
while ( temp->next != NULL )
{
next_free = temp->next;
free( temp );
temp = next_free;
}
*head = NULL;
}
Is this the correct approach?
To answer number 1, you can use what's called a dummy head. That is an empty node whose next pointer points to the first element in your list. So you create your empty list as a single node, and then pass that node around knowing that its pointer won't change. This is useful if you intend to store pointers to the head of your list in multiple places but allow the list to change.
For number 2, it's almost right, but you want to make sure that *head is not NULL initially. Also, it won't delete a list containing only one element. Do this instead:
while ( temp != NULL )
And leave everything else the same.
Oh, another note about your first question. You are wrong when you say this:
calling the function would only pass in the value of the address, the
caller would be unable to see any changes made to the head nor the
node.
The contents of the node can change. You don't need a double pointer to it. The double pointer means the pointer can change.
You can avoid the extra "next_free" variable by directly assigning to *head:
void deleteList( NODE_TYPE **head )
{
NODE_TYPE *temp;
while ( (temp = *head) )
{
*head = temp->next;
free( temp );
}
}
"My question is, is there another way to do this with a function prototype such as:
void addList( NODE *head, NODE *node)"
Well you are right. If you just "pass by value" the changes you reflect will not apply to the original subroutine. What you can do is this:
Node_type * addList(Node_type *head, Node_type *d_name)
{
d_name->next=head;
return d_name;
}
In the caller function call in this format
head = addList( head, node_3);
This would reflect the change you want to see
For Q2
Just put the condition
while(temp!=NULL)
This would take care of the condition where there is an empty list or a list with single node

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