ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Though I understand the logical usefulness of a linked list queue, I'm have no clue what the purpose, in a programming world, would be for a "simple queue structure", as found in the following code example. I hope someone can explain where such a construct would be useful.
(As this is from an online course in C programming, I've omitted the coding solutions)
Thanks for any help in my understanding.
Code:
/*************************************************************************
* queue.c
*
* Implements a simple queue structure for char*s.
************************************************************************/
#define _BSD_SOURCE
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> /* for strdup() in the testing code*/
#include <string.h>
// the capacity of the queue
#define CAPACITY 10
// a queue
typedef struct
{
// the index of the first element in the queue
int head;
// storage for the elements in the queue
char* strings[CAPACITY];
// the size of the queue
int size;
}
queue;
// declare a queue (as a global variable)
queue q;
/**
* Puts a new element into the queue into the "end" of the data structure
* so that it will be retrieved after the other elements already in the
* queue.FIFO
*/
bool enqueue(char* str) // TODO
{
}
/**
* Retrieves ("dequeues") the first element in the queue, following the
* the "first-in, first-out" (FIFO) ordering of the data structure.
* Reduces the size of the queue and adjusts the head to the next element.
*/
char* dequeue(void)
{
// TODO
// check if there are elements to dequeue
}
/**
* Implements some simple test code for our queue
*/
int main(void)
{
// initialize the queue
q.head = 0;
q.size = 0;
printf("Enqueueing %d strings...\n", CAPACITY);
for (int i = 0; i < CAPACITY; i++)
{
char str[10];
sprintf(str, "%d", i); //This inserts NUMBERS
enqueue(strdup(str));
}
printf("done!\n");
printf("Making sure that the queue size is indeed %d...", CAPACITY);
assert(q.size == CAPACITY);
printf("good!\n");
printf("Making sure that enqueue() now returns false...");
assert(!enqueue("too much!"));
printf("good!\n");
printf("Dequeueing everything...");
char* str_array[CAPACITY];
for (int i = 0; i < CAPACITY; i++)
{
str_array[i] = dequeue();
}
printf("done!\n");
printf("Making sure that dequeue() returned values in FIFO order...");
for (int i = 0; i < CAPACITY; i++)
{
char str[12];
sprintf(str, "%d", i);
assert(strcmp(str_array[i], str) == 0);
free(str_array[i]);
}
printf("good!\n");
printf("Making sure that the queue is now empty...");
assert(q.size == 0);
printf("good!\n");
printf("Making sure that dequeue() now returns NULL...");
assert(dequeue() == NULL);
printf("good!\n");
printf("Making sure that the head wraps around appropriately...");
for (int i = 0; i < CAPACITY; i++)
{
assert(enqueue("cs50!")); //This enqueues "cs50"
}
// to make sure that they adjust the head pointer appropriately, we'll
// enqueue and dequeue a bunch of times to make sure they don't just
// walk off the end of the char* strings[] array
for (int i = 0; i < CAPACITY * 10; i++)
{
for (int j = 0; j < CAPACITY / 2; j++)
{
assert(dequeue());
}
for (int j = 0; j < CAPACITY / 2; j++)
{
assert(enqueue("cs50!"));
}
}
printf("good!\n");
printf("\n********\nSuccess!\n********\n");
return 0;
}
Last edited by atlantis43; 11-15-2014 at 08:20 PM.
This is the code for a "First In First Out" (FIFO) queue. One example of an application for a queue like this would be where customers are waiting to be served at a counter. As they arrive, they can enter their name in the queuing application then sit down and wait for their name to be called. This system would also work if more than one counter used the same queuing application.
BTW I personally would use a "tail" index pointer rather than a "size" indicator. Each new arrival would advance the tail index pointer and each departure would advance the head index pointer. With provision for wrapping the pointers and keeping the tail behind the head, you have a simple coding project.
Yes, that was my main question, and the above info and link provided is an informative answer.
This brings up one further question: Would it be possible to enlarge the size of the contained queue (CAPACITY) within the struct node after the initial implementation of this code using functions such as realloc(), or would such a need demand the use of a linked list type of queue?
Last edited by atlantis43; 11-16-2014 at 04:47 AM.
It should be possible to use realloc() as long as your queue structure had the member char **strings; instead of char* strings[CAPACITY];.
You would probably want to use realloc() with a char **temp variable just in case the realloc() failed.
Of course, in this case you are still using the heap so it wouldn't be much better than using a linked list. Arrays work best if you know that you are going to have a fixed array size (not unusual in a queuing situation).
You often want a limited queue size. For example, at a telephone manual assistance centre, when all the operators are busy then incoming calls get placed in a queue. You don't want the queue to get too long otherwise the waiting times for the callers would become excessive and limited telephone circuits would be tied up. Better to dump the excess callers than to let the queue grow endlessly.
Size aside, there is one advantage that arrays have over linked lists; if you know the array index (and with hashing you usually do), you can access the desired record instantaneously. With linked lists, you always have to search for the record you want.
You often want a limited queue size. For example, at a telephone manual assistance centre, when all the operators are busy then incoming calls get placed in a queue. You don't want the queue to get too long otherwise the waiting times for the callers would become excessive and limited telephone circuits would be tied up. Better to dump the excess callers than to let the queue grow endlessly.
Size aside, there is one advantage that arrays have over linked lists; if you know the array index (and with hashing you usually do), you can access the desired record instantaneously. With linked lists, you always have to search for the record you want.
Good practical "worldly" example, but how would you keep the queue in proper order if phone call (eg: queue.size[27]) completes before queue.size[1]? Wouldn't a circular linked list %CAPACITY be more efficient, as you wouldn't have to move all elements of array to keep calls queued properly? With direct access, you would be able to place the new call in [27], but it would be out-of-order. Or am I missing something?
Last edited by atlantis43; 11-17-2014 at 06:48 AM.
The queue is for people waiting for an operator - not people who already have an operator. If an operator position becomes vacant then the person at the head of the queue gets that operator. If the queue is empty then the operator waits for an incoming call.
When a person calls the exchange, they get allocated to whichever operator is free. If there are no operators free then the person joins the tail of the queue. If the queue is full then the caller gets disconnected.
In effect you have two arrays: an operator array and a queue array.
The queue is for people waiting for an operator - not people who already have an operator. If an operator position becomes vacant then the person at the head of the queue gets that operator. If the queue is empty then the operator waits for an incoming call.
When a person calls the exchange, they get allocated to whichever operator is free. If there are no operators free then the person joins the tail of the queue. If the queue is full then the caller gets disconnected.
In effect you have two arrays: an operator array and a queue array.
Well, I understand what you say, but I don't think I know near enough to understand the programming advantages of such a "two-queue" system. ----maybe in a year or two-----?
Thanks again.
Well, I understand what you say, but I don't think I know near enough to understand the programming advantages of such a "two-queue" system. ----maybe in a year or two-----?
Thanks again.
Just to mention that I finally understand what you're telling me. Thanks again.
You need to store information about all of the operator positions; information such as whether the position is staffed, the operator is waiting for a call or details about the customer the operator is dealing with.
Since this information is independent of whether there are calls waiting in the queue, an array seems the logical choice to deal with all the operators. This is not a queue. In fact, you would want some algorithm that ensures that waiting operators are selected at random so that some positions are not busier than others.
The caller queue contains customers who do not have an operator yet. When an operator becomes available, the customer is removed from the queue and transferred to the operator.
I don't see how you could do that with a single queue - whether it is array based or a linked list.
Yes, you've made that extremely clear.
For fun, what follow is just to mention an anecdotal bit of telephone history from the antedeluvian days when human operators existed at switchboards:
Back in those days, when telephone etiquette was dictated by the phone company (AT&T), the rule they imposed on companies was that every call should be answered in <= 6 rings, or they would demand that more operators would be hired. Their copper wires wee valuable, and they didn't want lines tied up! they imposed a strict capacity on the array! :-)
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.