I'm having trouble figuring out how to insert an element into a sorted list. I am new to linked lists and I'm still having trouble.The following function takes an predefined list and an element as arguments. I have white boarded the whole thing but I still can't figure it out. Thank you for your help.
/*
* function: lst_insert_sorted
*
* description: assumes given list is already in sorted order
* and inserts x into the appropriate position
* retaining sorted-ness.
* Note 1: duplicates are allowed.
*
* Note 2: if given list not sorted, behavior is undefined/implementation
* dependent. We blame the caller.
* So... you don't need to check ahead of time if it is sorted.
*/
void lst_insert_sorted(LIST *l, ElemType x) {
NODE *p = l->front;
NODE *temp;
NODE *current = p;
NODE *prev;
NODE *next;
if (p->val >= x) { // Base Case if
p->val = x;
}
while (p !=NULL) {
prev = current;
temp = prev->next;
next = current->next;
if (next->val >= x) {
temp->val = x;
}
}
return 0;
}
You did not show how NODE is defined. So I suppose that the list is a single-linked list. In this case the function can look like
void lst_insert_sorted( LIST *l, ElemType x )
{
NODE *current = l->front;
NODE *prev = NULL;
while ( ( current != NULL ) && !( x < current->val ) )
{
prev = current;
current = current->next;
}
NODE *node = malloc( sizeof( NODE ) );
node->val = x;
node->next = current;
if ( prev != NULL )
{
prev->next = node;
}
else
{
l->front = node;
}
}
Generally speaking, a linked list consists of "nodes" joined together in sequence by links pointing from each node to the next one (or to the previous one, or both). The nodes each point also (perhaps trivially) to one of the actual elements of the list.
To insert an element into a linked list at a given position, you just create a node pointing to that element, and update the other pointers as needed. With a doubly-linked list such as yours (where each node points both to the next one and to the previous one), you must
update the next pointer of the node immediately preceding the insertion position to point at the new node,
update the prev pointer of the node immediately following the insertion position to point at the new node, and
set the prev and next pointers of the new node to point to these other nodes.
There are typically special cases for inserting at the beginning or end of the list; details depend on your list and node implementation.
In your case, you must also find an appropriate insertion point. Since the list is sorted, you can just traverse it from the beginning, comparing each node's element to the one to be inserted, until you find the right spot. Such a "linear search" is not terribly efficient if the list is long, but you cannot do better with a generic linked list.
if (p->val >= x) { // Base Case if
p->val = x;
}
there is a loss data so you wrote the x with overwriting in to first data in the list.
İf ı understood the problem you should create a node and insert this to list.
Related
I am trying to solve the Josephus problem using a linked list - https://en.wikipedia.org/wiki/Josephus_problem. Basically we have a specified number of people - let's say 6 with k being 3. I start counting from the start of the line/ circle of people and when k is reached, that person is eliminated. I then move onto the next person and k is reset and increased until the next person is reached. We do this until one person is remaining. Note - when counting people, we skip people that have already been eliminated. So in my example of 6 people and k = 3, the first person to be eliminated would be person 3 (or in array terms, index 2), with the last person to survive being person 1 (or index = 0).
I have already solved this problem using an array and for loops. However, now I want to try to solve using a linked list as that is what I am learning. I have already created my linked list. I think the logic here is the same, count through the nodes of the linked list and eliminate the node when k is reached and so on. My problem is that I don't know how to traverse through the linked list multiple times and how to successfully eliminate until there is one (node)remaining.
Firstly, creating the linkedlist with the specified number of people (valn):
int counter = 0;
ListNode * head = NULL;
head = malloc(sizeof(ListNode));
head -> value = counter;
ListNode *current = &head;
while ( valn - 1 > counter)
{
current -> next = malloc(sizeof*(current -> next));
current = current -> next;
current -> value = counter;
current -> next = NULL;
counter++;
}
Head is then returned to main (which is already provided so I am certain it is correct)
I then have a function that is supposed to count through the linked list and figure out which one to eliminate.
This is what I have so far (with valk being the number to eliminate), head and valkn are passed into this function (which is void):
int counter = 0;
ListNode * p = head;
while ( p != NULL)
{
if (counter == valk)
{
ListNode * todelete = p;
printListNode (todelete); // Print function that was already provided (already correct) - basically print the value of the node to be eliminated.
deleteNode(head,todelete); // passed on to another function to delete - not sure how to delete yet
counter = 0;
}
p = p -> next;
counter++;
}
The header file (all the relevant libraries are included. Header file was also given):
typedef struct node {
int value;
struct node * next;
} ListNode;
void printListNode(ListNode * head);
ListNode * createList(int valn);
void eliminate(ListNode * head, int valk);
ListNode * deleteNode(ListNode * head, ListNode * todelete);
Expected results are as described above, if my inputs are 6 and 3, I go through the linked list until the 1st (with value 0) node is remaining.
I have created a linked list of 5 nodes of type:
typedef struct node
{
int i;
struct node* link;
}node;
node* head = NULL;
When printing out, this gives:
4 3 2 1 0
The head pointer is set to point at 4. I have then written a function to bubble sort the linked list as follows:
void sort(void)
{
node* cur = head;
node* next = cur->link;
node* prev = NULL;
while(cur->i > next->i)
{
printf("cur is greater than next\n");
while(prev != head)
{
cur->link = next->link;
next->link = cur;
head = next;
next = cur->link;
prev = head;
}
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
printf("second while loop exited\n");
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
printf("%d", ptr->i);
}
cur = head;
next = cur->link;
}
}
There are various printf statements to check that the program is working. What I find is that after the first run-through, 4 is successfully bubbled up as follows:
3 2 1 0 4
However, after re-setting the cur pointer to 3 and next to 2, the next run-through provides the following:
2 1 0 4 3
Ultimately, we finish with
0 4 3 2 1
So as can be seen "3", "2" and "1" are being bubbled up too far. I have tried various conditonals in place of the third while loop to correct this but in the majority of cases this leads to seg faults. Of course, the other thing here is that my logic could be completely wrong and there may be a better way to implement this. Could you get away with just swapping the contents of nodes and not pointers themselves? Any help would be much appreciated. Thanks in advance
Ordinary bubble-sort implementations for sorting arrays make use of the direct addressing and a known size of the array: they naturally use indices, that is ordinal numbers of items, so they can easily shrink the area sorted as the work progresses, because they know how many items are already on their final places.
A linked list is processed purely sequentially, so it doesn't allow such simple optimization without adding artificial 'index', incremented along the list iteration. That's why it's easiest to iterate always through the whole list and terminate when no more items were swapped, hence the list is sorted:
void sort(void)
{
int swapped = 1;
while(swapped)
{
node **prev = &head, *curr, *next;
swapped = 0;
for(curr = head; curr; prev = & curr->link, curr = curr->link)
{
next = curr->link;
if(next && curr->i > next->i)
{
curr->link = next->link;
next->link = curr;
*prev = next;
swapped = 1;
}
}
}
}
EDIT – some explanations in reply to questions in Matthew2015 comments.
Logical conditions in C expect a numeric or pointer expression which are considered 'true' if they are different from zero or different from NULL, respectively. That means while(swapped) is essentially equivalent to while(swapped != 0) and next && ... is equivalent to next != NULL && .... The condition in while(swapped != 0) means the loop will terminate when some execution of internal for does not set swapped to 1, which happens when no item in the list is greater than its successor – that is, when the list is sorted.
The for loop condition expression is curr alone, equivalent to curr != NULL. That makes the for loop iterate along the list until there is no 'current' node.
The node **prev variable points to a pointer, which points to the current node. When the 'current' and the 'next' node need to be swapped, then the 'previous' link should no longer point to the 'current' node but to the 'next' node instead. Of course one might keep the pointer to the 'previous node' and assign a new value to the (previous node)->link — but that would not work in case of the first node in a list, which has no 'previous node' but is pointed to by the head variable. One must use additional condition to verify if the current node is the first node to resolve this inconsistency. Having a pointer to pointer, which originally points to head and then to 'previous node'.link makes the whole code much simpler, shorter and also a bit faster.
I would look at the third while
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
Here you're always moving elements without testing whether they have to be moved - i.e. cur->i > next->i.
By the way, if it's guard is true, the second while gets executed only once and so it's the same as an if so I would use an if, at least for clarity reasons.
i have a linked list like this :
1,jhon,19
2,sara,18
3,tom,20
4,jack,22
i have been trying forever to delete an element based on their id (witch is the first number). But in order to do that i need to delete this element from any position. so i came up with this code and i was wondering if it's correct :
temp1=head;
if(head!=NULL && head->id==givenID) // if the element is in the first position
{
temp = head;
head = head->next;
free(temp);
}
else if(head!=NULL && head->id!=givenID){// search for the element in the middle
do{
temp2=head;
head = head->next;
}while(head->id !=givenID && head->next !=NULL);
if(head->next !=NULL && head->id==givenID){// if the element is in the middle
temp2->next=head->next;
free(head);
head=temp1;
}
else if(head->next ==NULL && head->id==givenID){// if the element is in the last position
temp->next=NULL;
free(head);
head=temp1;
}
}
Thank you
This code is too complex, because it has unnecessary branches. You can unify your code by using a pointer to pointer.
The idea is to point your pointer to pointer to the head of the list, then to the next pointer of the initial element of the list, then to the next pointer of the second element of the list, and so on. The beauty of this approach is that no matter where you are in your list, the operation on a pointer to pointer remains the same!
Here is how it looks in code:
// Point your pointer to pointer to the head of the list
struct node **pptr = &head;
while (*pptr != NULL) {
// Dereference pptr to get the pointer to current node
node *current = *pptr;
// Check if the id of this node matches what we're looking for
if (current->id == givenID) {
// Here is the "magic": assign the next pointer of the current node
// to whatever is pointed to by pptr.
// It could be a head, or a next of some node.
*pptr = current->next;
free(current);
break;
}
pptr = &(current->next);
}
That's it! Since the pointer to pointer does not differentiate between head and other nodes, there is no additional checking going on.
Consider using a sentry node. All special cases disappear when you do.
This is how node erasure look in a linked list with sentry:
Iterator Erase( List* lst, Iterator here )
{
Iterator nxt = here->next;
Link( here->prev, here->next );
free( here );
lst->size -= 1;
return nxt;
}
with Link being no more complicated than
void Link( Iterator n1, Iterator n2 )
{
n1->next = n2;
n2->prev = n1;
}
All the other core functions, like insert etc. are similarly trivial.
I have a problem with my bubble-sorting function for the doubly linked list.
It is working when I'm sorting the nodes in the singly linked way (only with ->next), but I can't make it work with ->prev pointers.
Here is the code I'm using:
void sort(int count)
{
struct data *tmp,*current,*nextone;
int i,j;
for(i=0;i<count;i++)
{
current = first;
for(j=0;j<count-1-i;j++ )
{
if(current->number > current->next->number)
{
nextone = current->next;
current->next = nextone->next;
nextone->next = current;
if(current == first)
{
first = nextone;
current = nextone;
}
else
{
current = nextone;
tmp->next = nextone;
}
}
tmp = current;
current = current->next;
}
}
}
And this is the structure I'm using (with the global variables for the first and last element of the list):
struct data
{
int id;
char name[20];
int number;
struct data *next;
struct data *prev;
};
struct data *first = NULL;
struct data *last = NULL;
Below logic would work.
I would follow similar algorithm... If you want to move the entire nodes...
struct data *before, *after;
if(current->number > current->next->number)
{
before = current->prev;
after = current->next;
if(before != NULL){
before->next = after;
}
current->next = after->next;
current->prev = after;
after->next = current;
after->previous = before;
}
Alternatively, you can simply swap the numbers in the nodes without bothering to move entire nodes, if sorting of the data is the purpose. You can expand the below logic to include swapping of both char array and id as well.
if(current->number > current->next->number)
{
int tempNum = current->number;
current->number = current->next->number;
current->next->number = tempNum;
}
You just need to sit down and think about it for a bit.
Assigning first? Well the previous must be null.
Assigning last? Next must be null.
Anything else you need to do a little swap-dance with previous & next of the elements you are swapping.
A much easier way (that will quickly become faster too for larger array sizes) is to allocate an array of pointers, fill those with pointers to the elements, qsort the array then do another pass to re-wire the pointers (and delete the temp array).
One easier way is just to copy the data of the node, you can swap the data but the pointer to the node.
if(current->number > current->next->number){
swap(current->id,current->next->id);
swap(current->name,current->next->name);
swap(current->number,current->next->number);
}
With your method, you never set the previous pointer at all. You can sort the double linked list as single list at first, and then traversal the list again to set all the prev pointer.
Of course, you can sort the double linked list at a time, but it's a little complex to implement. You should consider 4 nodes each step, i.e current, current->next, as well as current->prev and current->next->next. When you want to swap current and current->next,
you should set current->prev->next=current->next, current->next=current->next->next so on and so forth.
I'm writing a hashtable as an array of linked lists.Currently I'm trying to have a simple hash table where the key is the index of the array and value is a singly linked list for implementing chaining.
This is my code to delete a node:
Basic Struct:
struct Node
{
int value;
int page;
struct Node *next;
};
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
for(;*iter;iter=&(*iter)->next)
{
if(page==((*iter)->page))
{
if(frame==((*iter)->value))
{
if(delete)
{
(*prev)->next=(*iter)->next;
free(*iter);
}
return 1;
}
}
prev=iter;
}
return 0;
}
For insertion please take a look here, AddNode
When I'm deleting a node, the value for that changes to 0. When I search for the node it gives back that node is not preset aka 0 as output from the function.
Are there any mistakes in my code which I haven't thought about?Am I leaving any memory leaks or any other problems?
Edit
Added this piece of code to the delete function:
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
struct Node** curr=iter;
for(;*curr;curr=&(*curr)->next)
{
if(page==((*curr)->page))
{
if(frame==((*curr)->value))
{
if(delete)
{
if(curr==iter)
{
iter=(*curr)->next;
free(*curr);
}
else
{
(*prev)->next=(*curr)->next;
free(*curr);
}
}
return 1;
}
}
prev=curr;
}
return 0;
}
Problem I'm seeing is that when I delete the first time, the element is not freed, it's value is set to 0, but it still says in the linked list. In the second deletion the value of the last elements goes to some garbage and hence that element will never be deleted in my comparison checks. Can someone shed light on what I might be doing here?
If the hash table you're using is seven elements wide (i.e. 0..6 for indexes), and from your AddNode code, it appears it is, then the arithmetic you're using is suspect for the initial iterator find.
iter=&hashtable[page-1%7];
should likely be:
struct Node** iter = hashtable + (page % 7);
This will give you the address of the element in your hash table at the page location modulus 7, i.e. [0..6].
Also, your delete from your hash table head node doesn't account for clearing the table element itself. You may need to (a) set it to null, or (b) chain in the next ptr. Do that as well. You have the ability to since the hash table and the initial node pointer are both available.
EDIT: OP asked for sample. This is just a quick jot of how this can be done. I'm sure there are plenty of better ways, maybe even ones that compile. This assumes both the page AND frame must match EXACTLY for a node to be considered delete'able.
void searchAndDelete(int frame, int page, int del)
{
struct Node** head = hashtable + (page % hashtable_size);
struct Node* curr = *head;
struct Node* prev = NULL;
while (curr)
{
// if they match, setup for delete.
if ((curr->page == page) && (curr->value == frame) && del)
{
// so long as the header pointer is the active node prev
// will be NULL. move head along if this is the case
if (prev == NULL)
*head = curr->next;
// otherwise, the previous pointer needs it next set to
// reference the next of our vicitm node (curr)
else
prev->next = curr->next;
// victim is safe to delete now.
free(curr);
// set to the new head node if we just deleted the
// old one, otherwise the one following prev.
curr = (prev == NULL) ? *head : prev->next;
}
else
{ // no match. remember prev from here on out.
prev = curr;
curr = curr->next;
}
}
}
Eh, close enough =P
I see couple of issues:
mod operator % needs parenthesis. So change iter=&hashtable[page-1%7]; to iter=&hashtable[(page-1)%7];
Handle the case when you will delete 1st element in linked list. In such cases prev will be same as iter so (*prev)->next=(*iter)->next; will not make any different. You need to update the array to store next element aka (*iter)->next.