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.
Related
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!
So, I've created a code where it creates a linked list with 5 values. I would like to know what would be the best method to remove duplicates of those values and print the linked list again without the duplicates.
#include <stdio.h>
#include <stdlib.h>
/* self-referential structure*/
struct studentID{
int value; //a data member which is an integer
struct studentID *next; //a data member which is a pointer to next node
};
typedef struct studentID STUDENTID; //creating a nickname for struct studentID as STUDENTID
typedef STUDENTID *STUDENTIDPtr; //creating a nickname for STUDENTID as STUDENTIDPtr
//Global variables
STUDENTIDPtr previousPtr; //pointer to previous node in list
STUDENTIDPtr currentPtr; //pointer to current node in list
void printList(STUDENTIDPtr currentPtr){
while (currentPtr != NULL){ //while not the end of the list
printf("%d -> ", currentPtr->value);
currentPtr = currentPtr ->next;
}
}
int main(){
STUDENTIDPtr newPtr1; //creating a pointer to create a new node
STUDENTIDPtr newPtr2; //creating a pointer to create a new node
STUDENTIDPtr newPtr3; //creating a pointer to create a new node
STUDENTIDPtr newPtr4; //creating a pointer to create a new node
STUDENTIDPtr newPtr5; //creating a pointer to create a new node
//creation of the first node
newPtr1 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr2 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr3 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr4 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr5 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr1 -> value = 4; // assign data in first node
newPtr1 -> next = newPtr2;
newPtr2 -> value = 4; // assign data in first node
newPtr2 -> next = newPtr3;
newPtr3 -> value = 5; // assign data in first node
newPtr3 -> next = newPtr4;
newPtr4 -> value = 2; // assign data in first node
newPtr4 -> next = newPtr5;
newPtr5 -> value = 1; // assign data in first node
newPtr5 -> next = NULL;
currentPtr = newPtr1;
printList(newPtr1);
return 0;
}
will using if else and run through every linked list be easy or is there a better method?
There are two approaches that come to mind right away, and which one to use depends on your specific case, and whether you'd like to preserve the original order of elements or not.
1st approach:
Use a double loop and pick up a node at a time. Then iterate the list after that node, and if you find a duplicate, remove. Repeat picking nodes, until you have iterated over the whole list.
For every node of the list
For every next_node after node
If next_node.value == node.value
Remove that next_node
This approach preserves the original order of the elements.
This approach is I think what you'd have already in mind. I suggest you start with that.
Example:
1 -> 2 -> 3 -> 4 -> 1
I will start from the first node (1), check the second node, the third, the fourth, nothing so far, no duplicates found. I now check the fifth node, which also has the value 1 (duplicate found!), so I remove it.
Now the list looks like this:
1 -> 2 -> 3 -> 4
Now I am looking of duplicates of the second node (I checked for the first node in the previous traversal). I check 3, I check 4, no duplicates found. The list remains the same.
Now I am looking of duplicates of the third node. I check 4, no duplicates found. The list remains the same.
Now I am looking of duplicates of the fourth node. The next node is NULL, which means that the fourth node is the last node (because we removed the fifth node in the first traversal, as a duplicate of 1). There is nothing to check then, the list remains the same:
1 -> 2 -> 3 -> 4
Observe how, for every node that I want to check if duplicates exist, I traverse the list until its end. So, for every node, I am doing an O(N) traversal, where N is the size of the list.
How many nodes do I have? N
So the Time Complexity of this approach is N * O(N) = O(N2)
I strongly recommend trying that out yourself, and practice. When you are done, you could read the Remove duplicates from an unsorted list to check your solution.
2nd approach:
Sort the list, and now the list will have the duplicate values grouped together. So, if there is a duplicate of the current node, it will be its next node. If it's a duplicate, remove next node.
Now, again, if there is a duplicate of the current node, it will be its next node. So do the same above, until the next node is not a duplicate of the current node.
Then, make next node the current node, and do the same process.
Sort list
current_node = head_node
While current_node != NULL
If current_node.value == current_node.next.value
Remove current_node.next
Else
current_node = current_node.next
This approach does not preserve the original order of the elements.
Same Example:
1 -> 2 -> 3 -> 4 -> 1
Sort the list:
1 -> 1 -> 2 -> 3 -> 4
I start from 1. I check its next node, it's also 1, a duplicate found! Remove the next node. Now the list is:
1 -> 2 -> 3 -> 4
Current node is still 1. I check its next node, it's 2. Not a duplicate. List remains the same. Set next node as the current node.
Current node is 2. Check its next node, it's 3, not a duplicate. List remains the same. Set next node as the current node.
Current node is 3. Check its next node, it's 4, not a duplicate. List remains the same. Set next node as the current node.
Current node is 4. It doesn't have a next node, nothing to check, I am done. List remains the same:
1 -> 2 -> 3 -> 4
Observe that for every node, I check only its immediate next node(s). And then, I continue for the last next node checked. That is O(N).
However, I had to sort the list, in order to ensure that the duplicates are grouped. Sorting a list can be done in O(NlogN).
The Time Complexity is O(NlogN) + O(N) = O(NlogN).
I had used Merge Sort to sort the list in C. There is also the Remove duplicates from sorted list for another explanation.
In the posted code you are "manually" adding every node if front of the list, so the first step would be to create a function that does that.
Then, you can create another function that will add a node in a list keeping it sorted. It will traverse the list finding the right location and will add a node only if it is not already there another node with the same value.
Now you can traverse the original list (the one which is not sorted) and for every node, try to add a copy of it to the sorted list. If it's already there, remove the node from the original list, otherwise add the copy to the sorted list.
At the end you will have two lists of unique elements, one of which sorted.
Don't forget to create a function that releases the allocated memory.
It seems you mean to remove not only adjacent duplicate values in the list.
What you need is to write a function that will accept the head node of the list by reference. The function can return the number of removed nodes.
Pay attention to that it is a bad idea to declare the global variables
//Global variables
STUDENTIDPtr previousPtr; //pointer to previous node in list
STUDENTIDPtr currentPtr; //pointer to current node in list
that moreover are redundant.
And this typedef can confuse readers of the code
typedef STUDENTID *STUDENTIDPtr;
Also you could write a separate function that adds a node to the list. You could initially to write the function such a way that the nodes in the list were ordered by the value.
As for the function that removes duplicate values then it can look the following way as iy is shown in the demonstrative program below. Investigate it.
#include <stdio.h>
#include <stdlib.h>
/* self-referential structure*/
struct studentID{
int value; //a data member which is an integer
struct studentID *next; //a data member which is a pointer to next node
};
typedef struct studentID STUDENTID; //creating a nickname for struct studentID as STUDENTID
typedef STUDENTID *STUDENTIDPtr;
size_t remove_duplicates( STUDENTIDPtr *head )
{
size_t n = 0;
for ( ; *head != NULL; head = &( *head )->next )
{
for ( STUDENTIDPtr *next = &( *head )->next; *next != NULL; )
{
if ( ( *head )->value == ( *next )->value )
{
STUDENTIDPtr tmp = *next;
*next = ( *next )->next;
free( tmp );
++n;
}
else
{
next = &( *next )->next;
}
}
}
return n;
}
void printList(STUDENTIDPtr currentPtr){
for ( ; currentPtr != NULL; currentPtr = currentPtr ->next )
{
printf("%d -> ", currentPtr->value);
}
puts( "NULL" );
}
int main(void)
{
STUDENTIDPtr newPtr1; //creating a pointer to create a new node
STUDENTIDPtr newPtr2; //creating a pointer to create a new node
STUDENTIDPtr newPtr3; //creating a pointer to create a new node
STUDENTIDPtr newPtr4; //creating a pointer to create a new node
STUDENTIDPtr newPtr5; //creating a pointer to create a new node
//creation of the first node
newPtr1 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr2 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr3 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr4 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr5 = malloc(sizeof(STUDENTID)); //This is when a node is created
newPtr1 -> value = 4; // assign data in first node
newPtr1 -> next = newPtr2;
newPtr2 -> value = 4; // assign data in first node
newPtr2 -> next = newPtr3;
newPtr3 -> value = 5; // assign data in first node
newPtr3 -> next = newPtr4;
newPtr4 -> value = 2; // assign data in first node
newPtr4 -> next = newPtr5;
newPtr5 -> value = 1; // assign data in first node
newPtr5 -> next = NULL;
printList( newPtr1 );
size_t n = remove_duplicates( &newPtr1 );
printf( "There are removed %zu elements\n", n );
printList( newPtr1 );
return 0;
}
The program output might look like
4 -> 4 -> 5 -> 2 -> 1 -> NULL
There are removed 1 elements
4 -> 5 -> 2 -> 1 -> NULL
Bear in mind that you need to write also a function that will free all allocated memory for the list.
The below solution is only for sufficiently small integer values, not extremely large ones.
What we can do here is take another array that can act as associative container.
Take an array. Initialize that array to 0.
Start to traverse the linked list.
if (arr[node->data] == 0); then increment arr[node->data]. This will make it 1, marking one occurrence.
else if (arr[node->data] == 1); then delete this node, as this means that the current node already contains an integer that has been encountered before.
You can implement a DS based on hashing or BST's, similar to cpp maps, to act as associative container, if you want to scale this up.
If you want a generic algorithm, I would encourage that you first write a brute-force logic along following lines --
Traverse the linked list
if the 'data' is found for the first time, then ignore and continue.
if the 'data' is found next time, invoke the logic of deletion.
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
Let's say I have the following struct:
struct object {
char *name;
struct object *next;
};
Using that I can easily create a table as a described in K&R C book. And remove all the objects by that:
object *object_destroy(object *obj)
{
if (obj != NULL) {
object_destroy(obj->next);
free(obj->name);
free(obj);
obj = NULL;
}
}
But what I want is to remove one of the objects in table, saving all the others. I really have no idea how to implement that, because just free() that object is won't work: the objects after it will be permamently lost. I can't obj_to_remove = obj_to_remove->next too, because after that I will lose all the objects before that object.
So can you point me out what I am missing? Thanks.
You are effectively attempting to delete a single node from a singly linked list (as opposed to a doubly-linked-list, or a circular list, also known as a ring buffer).
Please refer to the references below for more information on the concept of a singly linked list. In short, you:
Start at the first node in the list (the head node).
Cycle through the list one node at a time, keeping a pointer to the previously accessed node, until you find the node you want to delete.
Point the previous node in the list to the one ahead of the current/found node.
3.1. If there is no node afterwards (we are at the end of the list), set to NULL.
3.2. If the head/first node was the one found, set the head node to the second node in the list.
Delete the elements inside the node if the node has been found.
Delete the current node itself.
The second reference will be very helpful to you, as it covers building a list from scratch, adding items to the end of the list (appending), inserting items at an arbitrary point in the list, deleting individual items, and clearing out the whole list.
References
Deleting from a Linked List, Accessed 2014-04-22, <https://www.cs.bu.edu/teaching/c/linked-list/delete/>
Singly linked list - insert, remove, add, count source code, Accessed 2014-04-22, <http://www.cprogramming.com/snippets/source-code/singly-linked-list-insert-remove-add-count>
You have the following 1->2->3->4->5 and you want to remove the element 3. The final result will be 1->2->4->5.
To do this you just need to do the following steps:
1- If the element is in the middle of the list:
Traverse the table, for each element you save previous element and the element itself.
When the element equals the one you want to delete you have cur_el = 3 and prev_el = 2. (cur_el and prev_el are pointers to the elements 3 and 2)
Now just make prev_el->next = cur_el->next (don't forget to keep a pointer to the prev_el.
Finally just free the cur_el.
2- If the element is the first of the list (let's say you want to delete 1):
- Set the first list element as cur_el->next (here cur_el points to 1, the first element in the list)
free the cur_el
3- If the element is in the end of the list (in this case 5):
- go to the last element, get the penultimate element (let's call the pointer to this one prev_el)
set prev_el->next = null
free cur_el
Also, notice that removing an element from the list has a complexity of O(n), where n is the number of elements of the list.
If you just insert and remove from the begin or from the end you can reach a O(1).
In the question, the memory structure is referred to as a 'table'. Perhaps it would be better to call it a 'linked-list'.
int object_destroy(
object **head, /* The head of the linked-list is required in order to maintain proper list nodes linkage. */
object *obj
)
{
int rCode=0;
/* Unlink the node to be destroyed. */
if(*head == obj) /* Is the obj to destroy the head list node? */
*head = obj->next;
else
{
object *temp = *head;
/* Find the parent list node (to the one that will be destroyed). */
while(temp)
{
if(temp->next == obj)
break;
temp=temp->next;
}
/* Not found? */
if(NULL == temp)
{
rCode=ENOENT;
fprintf(stderr, "obj node not found in list\n");
goto CLEANUP;
}
/* Unlink the node, and patch the list so that remaining nodes are not lost. */
temp->next = temp->next->next;
}
/* Free the node to be destroyed. */
if(obj->name)
free(obj->name);
free(obj);
CLEANUP:
return(rCode);
}
I have to sort my linked list in specific way for example I have such linked list: 3->1->4->1->7->5->7 it has to be sorted like that: 7->1->7->1->3->4->5. So from what I understand I have to find for example max element in list and add it at beginning and delete such element from current list, I'm curious if is there any way to for example swap place of element in middle of list to beginning of list. Or I have to delete such element and allocate memory with given data and add it at beginning? Overall it's task from programming class test and has to be done using singly linked lists.
Here's one approach: given an unsorted list P:
Create a list Q.
Append max(P) to Q.
Remove max(P) from P.
Append min(P) to Q.
Remove min(P) from P.
Repeat steps 2 through 5 one more time.
Sort P in ascending order.
Append P to Q.
Q is now your sorted list.
This approach assumes P's length is no less than 4.
You can swap nodes in singly-linked lists if you have pointers to the list's node pointers, i.e the head pointer and the nodes' next pointers. You can do that because you have to walk the list anyway to find the maximum. (Be careful to chose the last maximum, otherwise subseqnet calls to this function will alwas bring the same 7 to the front.)
void max_to_front(struct node **head)
{
struct node **mp = head; // current max pointer address
struct node **pv = head; // iterator pointer address
struct node *nd = *head; // iterator pointer
int mx;
// nothing to do for empty or single-node lists
if (*head == NULL || (*head)->next == NULL) return;
// find maximum
mx = nd->value;
while (nd) {
if (nd->value >= mx) {
mp = pv;
mx = nd->value;
}
pv = &nd->next;
nd = nd->next;
}
// move max to the front, i.e. update the pointers
nd = *mp;
*mp = (*mp)->next;
nd->next = *head;
*head = nd;
}
Note how pv always contains the address of the node pointer via which you have come to the current node, nd, so you can update it; mp is just the pointer address for the node with the maximum value.