Making A Queue with LinkedList in C - c

So I was going through a textbook example of how to make a queue from a linked list in C and I'm kinda of stuck on how exactly a piece of codes works.
So the example the textbook uses is a queue that helps models passengers waiting in line to be served by a ticket agent.
They start off by defining the structure of how the queue will be implemented:
/* Insert typedef for queue_element_t */
typedef struct queue_node_s {
queue_element_t element;
struct queue_node_s *restp;
} queue_node_t;
typedef struct {
queue_node_t *frontp,
*rearp;
int size;
} queue_t;
Then they go on to show the implementation of two functions:
void add_to_q(queue_t *qp, queue_element_t ele);
queue_element_t remove_from_q(queue_t *qp);
The first function is defined as:
/*
* Adds ele at the end of queue accessed through qp
* Pre: queue is not empty
*/
void
add_to_q(queue_t *qp, /* input/output - queue */
queue_element_t ele) /* input - element to add */
{
if (qp->size == 0) { /* adds to empty queue */
qp->rearp = (queue_node_t *)malloc(sizeof (queue_node_t));
qp->frontp = qp->rearp;
} else { /* adds to non-empty queue */
qp->rearp->restp =
(queue_node_t *)malloc(sizeof (queue_node_t));
qp->rearp = qp->rearp->restp;
}
qp->rearp->element = ele; /* defines newly added node */
qp->rearp->restp = NULL;
++(qp->size);
}
Similarly remove_from_q is implemented in the following way:
/*
* Removes and frees first node of queue, returning value stored there.
* Pre: queue is not empty
*/
queue_element_t
remove_from_q(queue_t *qp) /* input/output - queue */
{
queue_node_t *to_freep; /* pointer to node removed */
queue_element_t ans; /* initial queue value which is to
be returned */
to_freep = qp->frontp; /* saves pointer to node being
deleted */
ans = to_freep->element; /* retrieves value to return */
qp->frontp = to_freep->restp; /* deletes first node */
free(to_freep); /* deallocates space */
--(qp->size);
if (qp->size == 0) /* queue's ONLY node was deleted */
qp->rearp = NULL;
return (ans);
}
When I go through it by myself, I find that I am still somewhat confused as to why it works this way? Correct me if I'm wrong here: On the first call to the function add_to_q, we assume that the queue is initially empty so the queue_node_t pointers frontp and rearp both point to the same spot in memory allocated in heap. Thus as a result, frontp->restp == rearp->restp, which is why you are allowed to write the line
qp->frontp = to_freep->restp;
in remove_from_q? Plus, on the second call to add_to_q, when you add a second element frontp points to the same memory locate but rear moves to a new location?
My follow up to that would be that once one element is in the queue, if we go and add a new member to the back of the queue, how does the following block of code give us the correct functionality that we expect of our queue?:
else { /* adds to non-empty queue */
qp->rearp->restp =
(queue_node_t *)malloc(sizeof (queue_node_t));
qp->rearp = qp->rearp->restp;
}
qp->rearp->element = ele; /* defines newly added node */
qp->rearp->restp = NULL;
++(qp->size);
}
I've tried drawing this out in terms of memory blocks, but I don't see how once the program gets to the line qp->rearp = qp->rearp->restp;, when you write qp->rearp->restp = NULL; it doesn't also set qp->rearp equal to NULL as well since they should (to my knowledge) be pointing to the same spot in memory.
Any guidance would be greatly appreciated!!!
Thanks :)

let's have some brief overview :
Queue is a linear data structure, in which the first element is inserted from one end called REAR, and the deletion of exisiting element takes place from the other end called as FRONT.
KeyPoint: The process to add an element into queue is called Enqueue(insertion) and the process of removal of an element from queue is called Dequeue(deletion).
Now, I've created two design to let you understand the basic concept of insertion and deletion.
1. Insertion( also creation)
2. Deletion in Queue :
I hope you will understand the basic concept of queue using linked-list so that, you do not confused in future and can learn further.

A queue is a first in first out structure (I guess you already know that). This particular code implements it using a linked list. What it basically does is whenever you "enqueue" some data you add it at the rear end of the linked list (the tail). Thus, rear gets modified on every call of add_to_q.
My follow up to that would be that once one element is in the queue, if we go and add a new member to the back of the queue, how does the following block of code give us the correct functionality that we expect of our queue?:
qp->rearp points to the last node (the rear of the code). qp->rearp->restp is the so called "next" pointer of that node. qp->rearp->restp=malloc... makes a new node at the "next" of the old rear. qp->rearp=qp->rearp->restp makes qp->rearp point to the new rear. qp->rearp->restp makes the "next" of the last node NULL.
So the code basically adds new nodes at the tail end of the linked list and removes nodes from the head end (the other way around should be more efficient). They are using the word "rearp" because you are supposed to go stand at the "rear" of a queue.
This is basically dealing with a linked list while keeping a "tail" pointer as well as a "head" pointer for efficiency purposes.

I'd suggest drawing it out again (and again), with blocks and pointers. First, make sure you understand a simple linked list that uses only a head and next pointers. Then progress to this one that maintains the head, tail and size info. Your comments actually sound like you mostly got it, right down until your last comment about setting the last elements next pointer to NULL. (Hint: qp->rearp is now our last node, we put the element in it, and set it's 'next' pointer to NULL)

Related

Why do I override my struct? Implementing queues but it doesn'work

I need to program queue structs in C for an assignment. The nodes have a pointer to the next node and the value (so far, so normal). But, as I need to use it with threads, I shall malloc all of the capacity on the heap.
However, the nodes and queues are defined like this:
//Element of a queue
struct queue_node {
// Pointer to next element in the queue
struct queue_node* next;
// Value/Data of the queue element
int value;
};
// Queue data structure
struct queue {
// Head of the linked list
struct queue_node* head;
// Max capacity of the queue
int capacity;
// Current size of the queue. size <= capacity, always
int size;
};
The problem I got with this, was to push elements, as I don't have any information on which is the start or the end of the allocated memory. So I decided to make the head node always the first one in the space, so I could work with the capacity
And I programmed the basic functions like this:
struct queue* queue_new(int capacity){
struct queue_node* head1 = malloc(sizeof(struct queue_node)*capacity);
struct queue* ret = malloc(sizeof(struct queue));
/*
struct queue_node head2;
head2.next = NULL;
(*head1) = head2;
*/
(*head1).next = NULL;
(*ret).head = head1;
(*ret).size = 0;
(*ret).capacity = capacity;
return ret;
}
void queue_delete(struct queue* queue){
free((*queue).head);
free(queue);
}
So. But, I get trouble, when I want to push something into the queue. Obviously, the first thing to do, is to fill the head. And that seems to work. But appending an element to the head node doesn't:
int queue_push_back(struct queue* queue, int value){
if((*queue).size >= (*queue).capacity){
return -1;
}else if((*queue).size == 0){
(*(*queue).head).value = value;
(*queue).size++;
return (*queue).size;
} else{
if((*(*queue).head).next == NULL){ ////((*queue).head + sizeof(struct queue_node))
printf("Intern queue size 1: %d\n", (*queue).size);
(*(*queue).head).next = ((*queue).head + sizeof(struct queue_node));
printf("Error here?\n");
(*(*(*queue).head).next).value = value;
printf("Error here 2?\n");
(*(*(*queue).head).next).next = NULL;
printf("Error here 3?\n");
printf("Intern queue size 2: %d\n", (*queue).size);
printf("Intern queue capacity: %d\n", (*queue).capacity);
(*queue).size++;
return (*queue).size;
}
}
I skipped the code for the common case, because this doesn't even works. For some reason, if I want to push a second element, it overrides my queue struct. And I have no idea why.
Can someone help me and tell me, where I did something wrong?
You seem to be trying to mix two different approaches to the problem:
Maintaining the queue as an array, and
Maintaining the queue as a linked list.
Allocating space for the full complement of nodes in one block, keeping the queue head at the beginning of the block, and indeed having a fixed queue capacity in the first place, are all characteristic of array-like use. On the other hand, having element node structures with 'next' pointers is the form of a linked list.
If you manage the queue as an array, then the next pointers are redundant, and indeed they are constricting if you actually use them. Instead, you can always identify and navigate to a node by means of the pointer to the start of the block of nodes and a node index: my_queue_ptr->head[node_num]. You can also identify the next available node based on the queue's current size: my_queue_ptr->head[my_queue_ptr->size].
But then whenever you dequeue a node, you have to move all the other nodes -- or at least their data -- one position forward. If you move the whole nodes, then you screw up their next pointers, because the thing at each pointed-to location is different, and has different significance, from what was there before.
On the other hand, if you manage the queue as a linked list then it does not make sense to allocate all the nodes in one block. It would instead be conventional to allocate a new node for each value you enqueue, and to deallocate the node of each value that you dequeue. In that case you will modify the queue's head pointer upon enqueueing the first element and upon dequeuing any element. If you do not maintain a pointer to the current tail as well (as presently you don't), then every time you enqueue an element you'll need to walk the list to find the tail node, and append the new node there.
Update:
In the event that you nevertheless proceed with what you describe, the only way forward that makes sense to me is to adopt the array-based approach, and ignore altogether the linked-list aspects of the data structures. The queue_new() and queue_delete() functions you presented are reasonable for this. Your queue_push_back(), on the other hand, isn't even internally consistent, much less appropriate for the array-like approach.
Before, I go into details, however, I want to point out that your code is unnecessarily hard to read. Surely you have been introduced to the -> operator by this point; it is specifically designed to ease use of pointers to structures, and especially to easy use of chains of pointers to structures. Here is the first part of your queue_push_back() function, rewritten to use ->; the part presented is exactly equivalent to the corresponding part of your original:
int queue_push_back(struct queue* queue, int value){
if (queue->size >= queue->capacity) {
return -1;
} else if (queue->size == 0) {
queue->head->value = value;
queue->size++;
return queue->size;
} else {
// ...
}
That's much easier to read, at least for me. Now, with fewer distractions, it's easier to see that the only attribute of the head node that you set is its value. You do not set its next pointer. If you've understood my recommendation then you'll recognize that that's in fact just fine -- you'll be using indices into the array to access elements, not links, which would be at best redundant.
But now consider what you try to do when you push the next element. The very first thing is to test the value of the head node's next pointer, which you never set. Undefined behavior results. Now you could manage the links and use them (though you'd need something more sophisticated than what you now have if you want to support queues with capacity greater than 2), but as I said, my recommendation is to ignore the links altogether.
Having already verified that the queue has room for another element, you can access that element directly as queue->head[queue->size]:
queue->head[queue->size].value = value;
queue->size++;
And Lo, that's all there is to it. But wait, it gets better! If you look carefully, you'll see that there's very little difference between the case of the first node and the case of the others. In fact, the difference is purely syntactic; the first node (when queue->size == 0) would be equally well served by the code I've just presented; it doesn't need to be a special case at all:
int queue_push_back(struct queue* queue, int value){
if (queue->size >= queue->capacity) {
return -1;
} else {
queue->head[queue->size].value = value;
return ++queue->size;
}
// That's all, folks!
}

C Code: Efficient way to parse through to end of LinkedList

I have a Struct Data, this will be a Linked List of Messages. For every new message, I need to append at the last in linked List. I have a Counter where I know how many messages are present.
Instead of parsing till the end of the linked List. Is there any better way to get to the specific position in Linked List??
struct Data {
char *message;
struct Data *next;
}data;
int total_message;
Right now I am parsing like below:
struct Data *traverse;
while(traverse->next != NULL)
traverse = traverse->next;
I tried below as well, I am not sure why this wrong logically it seems right to me.
data[total_messages - 1].next = new_data;
Is there any better way other than storing pointer to Last Message?
Consider maintaining a pointer to the tail of the linked list.
data * head = NULL;
data * tail = NULL;
void Append(data * entry) {
if (!head) {
head = entry;
}
if (tail) {
tail->next = entry;
}
tail = entry;
}
Why traversing (as in the question) is bad?
If we maintain only the head and the number of messages say n, then for each append we have to traverse the n linked nodes starting from head -- that's O(n) operation -- slightly inefficient. If adding to the tail of the list is a frequent operation -- as it seems in your case -- then maintaining the tail pointer is efficient. Space wise, maintaining a counter is same as maintaining a pointer.
Why the following is bad?
data[total_messages - 1].next = new_data;
That's an array notation. Arrays are contiguous block of memory. In linked list, the nodes could be anywhere in memory, they cannot be accessed in array notation like that.
The [] syntax works for arrays because arrays arrange their data in a line, in a predictable way. Linked lists do not. You can only find out where the ith element is by following the next pointers.
data[i] refers to the data i places after the memory address data, which is unlikely to be at the location of a Data struct. Writing data to that position will generally just disrupt a random section of code somewhere else in the program.
A fast and relatively simple solution is to push each new element onto the front of the list while parsing, and then reverse the list in place once you have pushed all the elements.

Reverse a linked list using recursion in C

I was trying the reversal of a linked list using recursion. I viewed the sample program in geeksforgeeks website. They had a good explanation. But I could not understand what the *headref will hold on every stack unwinding. Doesnt it hold the next address during every stack unwinding, if its that way then how does the rest value is same during all the stack unwinding calls. The first value gets changed during the stack unwinding and so is the rest value. Why doesnt rest value is not changed when the first value is changed for every stack unwinding. Please help to understand.
void recursiveReverse(struct node** head_ref)
{
struct node* first;
struct node* rest;
/* empty list */
if (*head_ref == NULL)
return;
/* suppose first = {1, 2, 3}, rest = {2, 3} */
first = *head_ref;
rest = first->next;
/* List has only one node */
if (rest == NULL)
return;
/* reverse the rest list and put the first element at the end */
recursiveReverse(&rest);
first->next->next = first;
/* tricky step -- see the diagram */
first->next = NULL;
/* fix the head pointer */
*head_ref = rest;
}
Once the 'rest list' got reversed in the recursive step, its first item, pointed at by rest, became its last item, so the previous 'first' gets appended after that. Then it is the last item, so its next member becomes NULL. Finally we return the new head through the call parameter.
The head is changed in every recursive call.
Each recursive call takes the sublist [k,n] , where k is the previously parsed elements.
The first entry is [0,n] , which in the code above is [first,rest] .
Initially links are from first to rest.
Before each recursive call rest gets linked to first having a temporary loop inside the list (first points to rest, rest points to first).
Then , after the recursive call returns, the loop is killed by removing the first to rest link and putting first to be rest's next . (basically keeping only the inverse order).
As any single linked list, the last element needs to have no childern, and right now first is the last element, so first->next becomes null.
The new head of the list is the last element, which in this case will be rest , which gets passed on from the deepest recursion upwards.
This algorithm is so much faster and easier to implement with an iterative approach.
Problem of such algorithm is memory consumption required by recursive calls.
You have one parameter pointer and two var pointer, each call that goes on top of the memory stack. But it is the reason it works and the var is not changed. It does not reference the same memory area.
You can note that an iterative approch is faster and easier in fact.
void iterativeReverse(struct node** head_ref) {
struct node *prev=NULL, *next;
while (*head_ref) {
next=*head_ref->next;
*head_ref->next=prev;
prev=*head_ref;
*head_ref=next;
}
*head_ref=prev;
}

Marking the head reference to the tail of the linked list

The iterative way of reversing a linked list is very easy way to do. I tried to understand the recursive way by going through the below link
http://www.geeksforgeeks.org/write-a-function-to-reverse-the-nodes-of-a-linked-list/
void recursiveReverse(struct node** head_ref)
{
struct node* first;
struct node* rest;
/* empty list */
if (*head_ref == NULL)
return;
/* suppose first = {1, 2, 3}, rest = {2, 3} */
first = *head_ref;
rest = first->next;
/* List has only one node */
if (rest == NULL)
return;
/* reverse the rest list and put the first element at the end */
recursiveReverse(&rest);
first->next->next = first;
/* tricky step -- see the diagram */
first->next = NULL;
/* fix the head pointer */
*head_ref = rest;
}
We first move the pointer to the tail of the linked list.
During stack unwinding we stitch the links reversely.
But for all the stack unwinding calls, *headref = rest . So as first is changing during the stack unwinding to the previous stack value, why doesnt the rest too didnt change. I created 4 nodes and viewed the values through the gdb. The rest values during stack unwinding remained constant but the first values are changing. Why is it rest not changing.
While thinking in terms of changing pointers and values is a good way
to think about iterative programs, it is a confusing way to look at
recursive programs, because each recursive call creates its own local
variables, all with the same names, but possibly different values.
With a recursive function it is more helpful to assume that it works correctly for input of size n, and then verify its correctness for input of size n+1. If the "base case" (size 0 or 1) is covered, this then proves that it works for all inputs
In your case, let's suppose that recursiveReverse works OK for lists of length 3, and let's feed it a list of length 4 a->b->c->d by
calling recursiveReverse(&p) where p=a
Both first->next and rest will be b, hence point to a 3-element list b -> c -> d, so (by our assumption)
recursiveReverse(&rest) will correctly reverse this list. After the
call, rest has changed value (from b to d) and now points to this reversed list d->c->b
first->next is still the same pointer b as before the call, and therefore now points to the end of the list.
Thus, first->next->next = first attaches first to the end of this reversed list, which then becomes d->c->b->a)
As first is now the end of the list, we now need first->next = NULL. The final step is to change *head_ref (from a to d), so, after returning from recursiveReverse(&p), p will have changed from a to the new head of the list, d.
This shows that whenever the function works correctly for n-element
lists, it works correctly for n+1-element lists. The base case is easy,
so whe have shown that it works for all lists.
Now, why don't you see rest changing value in your debugger? Because
its value is only ever changed by the function call
recursiveReverse(&rest). Before you recursively call
recursiveReverse it has one value, after you return from it it has
another, you don't see it changing when stepping in and out of each function call. The assignment that changes its value is actually the very last (*head_ref = rest) before the function returns, but the assignee is called head_ref in this stack frame, not rest (as it was called in the stack frame of the caller)
This is the "same names, but different values" confusion I mentioned above.

Struct - remove one of the elements

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);
}

Resources