# Exercise 17.4

file: `4_mall.c`

``````// compile with 4_queue.c
#include <stdio.h>
#include <stdlib.h>    // for rand() and srand()
#include <time.h>      // for time()
#include "4_queue.h"     // change Item typedef
#define MIN_PER_HR 60.0
bool newcustomer(double x);  // is there a new customer?
Item customertime(long when); // set customer parameters
int main(void)
{
Queue line1;
Queue line2;
Item temp;                 // new customer data
int hours;                 // hours of simulation
int perhour;               // average # of arrivals per hour
long cycle, cyclelimit;    // loop counter, limit
long turnaways = 0;        // turned away by full queue
long customers = 0;        // joined the queue
long served = 0;           // served during the simulation
long sum_line1 = 0;         // cumulative line length
long sum_line2 = 0;
int wait_time1 = 0;        // time until line 1 is free
int wait_time2 = 0;        // time until line 2 is free
double min_per_cust;       // average time between arrivals
long line_wait1 = 0;        // cumulative time in line
long line_wait2 = 0;
InitializeQueue(&line1);
InitializeQueue(&line2);
srand((unsigned int) time(0)); // random initializing of rand()
puts("Case Study: Sigmund Lander's Advice Booths (2 booths version)!");
puts("Enter the number of simulation hours:");
scanf("%d", &hours);
cyclelimit = MIN_PER_HR * hours;
puts("Enter the average number of customers per hour:");
scanf("%d", &perhour);
min_per_cust = MIN_PER_HR / perhour;
for (cycle = 0; cycle < cyclelimit; cycle++) {
if (newcustomer(min_per_cust)) {
if (QueueIsFull(&line1) && QueueIsFull(&line2))
turnaways++;
else {
customers++;
temp = customertime(cycle);
// customer choose shortest line
if (QueueItemCount(&line1) < QueueItemCount(&line2))
EnQueue(temp, &line1);
else
EnQueue(temp, &line2);
}
}
if (wait_time1 <= 0 && !QueueIsEmpty(&line1)) {
DeQueue(&temp, &line1);
wait_time1 = temp.processtime;
line_wait1 += cycle - temp.arrive;
served++;
}
if (wait_time1 > 0)
wait_time1--;
sum_line1 += QueueItemCount(&line1);
if (wait_time2 <= 0 && !QueueIsEmpty(&line2)) {
DeQueue(&temp, &line2);
wait_time2 = temp.processtime;
line_wait2 += cycle - temp.arrive;
served++;
}
if (wait_time2 > 0)
wait_time2--;
sum_line2 += QueueItemCount(&line2);
}
if (customers > 0) {
printf("customers accepted: %ld\n", customers);
printf("customers served: %ld\n", served);
printf("turnaways: %ld\n", turnaways);
printf("average queue size: %.2f\n",
(double) (sum_line1 + sum_line2) / (cyclelimit * 2));
printf("average wait time: %.2f minutes\n",
(double) (line_wait1 + line_wait2) / (served * 2));
}
else
puts("No customers!");
EmptyTheQueue(&line1);
EmptyTheQueue(&line2);
puts("Bye!");
return 0;
}

// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
if (rand() * x / RAND_MAX < 1)
return true;
else
return false;
}

Item customertime(long when)
{
Item cust;
cust.processtime = rand() % 3 + 1;
cust.arrive = when;
return cust;
}``````

file: `4_queue.c`

``````#include <stdio.h>
#include <stdlib.h>
#include "4_queue.h"

/* local functions */
static void CopyToNode(Item item, Node * pn);
static void CopyToItem(Node * pn, Item * pi);

void InitializeQueue(Queue * pq)
{
pq->front = pq->rear = NULL;
pq->items = 0;
}

bool QueueIsFull(const Queue * pq)
{
return pq->items == MAXQUEUE;
}

bool QueueIsEmpty(const Queue * pq)
{
return pq->items == 0;
}

int QueueItemCount(const Queue * pq)
{
return pq->items;
}

bool EnQueue(Item item, Queue * pq)
{
Node * pnew;
if (QueueIsFull(pq))
return false;
pnew = (Node *) malloc( sizeof(Node));
if (pnew == NULL) {
fprintf(stderr,"Unable to allocate memory!\n");
exit(1);
}

CopyToNode(item, pnew);
pnew->next = NULL;
if (QueueIsEmpty(pq))
pq->front = pnew;
else
pq->rear->next = pnew;
pq->rear = pnew;
pq->items++;
return true;
}

bool DeQueue(Item * pitem, Queue * pq)
{
Node * pt;
if (QueueIsEmpty(pq))
return false;
CopyToItem(pq->front, pitem);
pt = pq->front;
pq->front = pq->front->next;
free(pt);
pq->items--;
if (pq->items == 0)
pq->rear = NULL;
return true;
}

void EmptyTheQueue(Queue * pq)
{
Item dummy;
while (!QueueIsEmpty(pq))
DeQueue(&dummy, pq);
}

static void CopyToNode(Item item, Node * pn)
{
pn->item = item;
}

static void CopyToItem(Node * pn, Item * pi)
{
*pi = pn->item;
}``````

file: `4_queue.h`

``````#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <stdbool.h>

typedef struct item {
long arrive;
int processtime;
} Item;

#define MAXQUEUE 10

typedef struct node
{
Item item;
struct node * next;
} Node;

typedef struct queue
{
Node * front; /* pointer to front of queue */
Node * rear;  /* pointer to rear of queue */
int items;    /* number of items in queue */
} Queue;

/* operation: initialize the queue                    */
/* precondition: pq points to a queue                 */
/* postcondition: queue is initialized to being empty */
void InitializeQueue(Queue * pq);

/* operation: check if queue is full                        */
/* precondition: pq points to previously initialized queue  */
/* postcondition: returns True if queue is full, else False */
bool QueueIsFull(const Queue * pq);

/* operation: check if queue is empty                        */
/* precondition: pq points to previously initialized queue   */
/* postcondition: returns True if queue is empty, else False */
bool QueueIsEmpty(const Queue *pq);

/* operation: determine number of items in queue            */
/* precondition: pq points to previously initialized queue  */
/* postcondition: returns number of items in queue          */
int QueueItemCount(const Queue * pq);

/* operation: add item to rear of queue                     */
/* precondition: pq points to previously initialized queue  */
/*               item is to be placed at rear of queue      */
/* postcondition: if queue is not empty, item is placed at  */
/*                rear of queue and function returns        */
/*                True; otherwise, queue is unchanged and   */
/*                function returns False                    */
bool EnQueue(Item item, Queue * pq);

/* operation: remove item from front of queue                 */
/* precondition: pq points to previously initialized queue    */
/* postcondition: if queue is not empty, item at head of      */
/*                queue is copied to *pitem and deleted from  */
/*                queue, and function returns True; if the    */
/*                operation empties the queue, the queue is   */
/*                reset to empty. If the queue is empty to    */
/*                begin with, queue is unchanged and the      */
/*                function returns False                      */
bool DeQueue(Item *pitem, Queue * pq);

/* operation: empty the queue                               */
/* precondition: pq points to previously initialized queue  */
/* postconditions: the queue is empty                       */
void EmptyTheQueue(Queue * pq);

#endif``````