91.102 - computing ii abstract data types: queues and stacks. implementation: queues and stacks....

57
91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which these topics should be covered is somewhat unclear: historically the application programs suggested to the programmers some groupings of data and some operations. These were often implemented in ad-hoc ways, without much thought for “general issues”. As the types of structures and the associated operations kept reappearing in many different contexts, people began developing “general theories”.

Upload: candace-hubbard

Post on 11-Jan-2016

241 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Abstract Data Types: Queues and Stacks.

Implementation: Queues and Stacks.

Applications of Queues and Stacks.

The order in which these topics should be covered is somewhat unclear: historically the application programs suggested to the programmers some groupings of data and some operations. These were often implemented in ad-hoc ways, without much thought for “general issues”. As the types of structures and the associated operations kept reappearing in many different contexts, people began developing “general theories”.

Page 2: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Queue: people queue up to get on a bus; people queue up in front of a bank teller (if the banks have their way, it will be only in front of an ATM machine); people queue up at a checkout counter at a store; network packets queue up at a switch; processes queue up in a computer waiting for the CPU; ships queue up to cross the isthmus of Panama - or at the Suez Canal; airplanes queue up for takeoffs and landings; cars queue up at tollbooths and traffic lights; etc...

Page 3: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Let’s think about the car queue: as the light turns red, the queue is empty (it’s not a very busy road…), then a first car arrives, a second one, and so on…

Page 4: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

Eventually, the light turns green and the first car goes through, then the second, and so on: the cars go through the light in the same order in which they stopped (and entered the queue).

91.102 - Computing II

Page 5: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

This order can be represented as a sequence, i.e. a function from the natural numbers to this set of cars:

{1, 2, 3, 4, …} {car1, car2, car3, car4, …}.

(you may see {0, 1, 2, 3, …}: 0 may or may not be there, depending on the author - mathematical logicians define 0 as a natural number)

Page 6: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

A bit more formally: we have a set U, the Universe, from which we take the individual items to be queued. This could be a set of cars, of people, of processes, of integers, of structs, etc… the only important requirement is that the items be “all of the same type”.

A queue is a finite sequence with range in U:

Q : {1, 2, 3, 4, …, n} U

Notice that finite sequences do not require uniqueness: we could have two integers i and j mapping to the same element of U. This may not be very meaningful in our context - and is unlikely to occur often.

Page 7: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Actually, this is not enough of a definition: we need to know a bit more about the functionality of this creature. In particular, we need to know how to define such sequences from nothing, via some kind of a constructor function or procedure that allows us to construct the sequence one element at a time, and we need to know how to destroy the sequence one element at a time. It is the "destruction function" that is of particular interest to us.

So: (the Greek capital lambda) will denote the empty set, or the empty sequence, or, in this case, the empty queue.

Page 8: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Initialize(Q)

this gives us an empty queue named Q.

The constructor function will take as parameters an item x from the Universe and a queue Q (empty or not) and will construct a new queue, containing the element x. We will, in general, still use Q to denote this changed queue.

Insert(x, Q) Q.

Page 9: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

The destructor function must take a queue Q as a parameter and return both an item and the changed queue, from which the item is now missing. We will use Q to denote this changed queue:

Remove(Q) (x, Q).

The functional requirement is: The order of removal of items in the queue is exactly the same as the order of insertion:

Page 10: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Insert(Ferrari_TR, Q)

Insert(Lamborghini_Diablo, Q)

Insert(McLaren_F1, Q)

Q 3McLaren_F12Lamborghini_Diablo1Ferrari_TR

Page 11: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

Remove(Q)

Remove(Q)

Remove(Q)

Q 3McLaren_F12Lamborghini_Diablo

91.102 - Computing II

1Ferrari_TR1Lamborghini_Diablo 2McLaren_F11McLaren_F1

Page 12: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Stacks: another type of sequences.

Three stacks of coins: add new coins to the top, remove coins from the top. Always remove first the last item you added.

Page 13: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

We need:

The empty stack , so that we can have S = .

Initialize(S) - this gives us an empty stack named S.

A constructor function:

Insert(x, S) S, where the new stack contains x.

A destructor function:

Remove(S) (x, S), where the new stack does not contain x.

Page 14: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

We can describe the Last-In-First-Out property as follows:

Remove(Insert(x, S)) (x, S);

Insert(Remove(S)) = Insert(x, S’) S

Where S is the same stack at the beginning and at the end of the operations, while S’ is the stack S after removal of its "top" element.

91.102 - Computing II

Page 15: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Example:

91.102 - Computing II

Insert(Ferrari_TR, S)

Insert(Lamborghini_Diablo, S)

Insert(McLaren_F1, S)

S 3McLaren_F12Lamborghini_Diablo1Ferrari_TR

Page 16: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Remove(S)

Remove(S)

Remove(S)

S 3McLaren_F12Lamborghini_Diablo

91.102 - Computing II

1Ferrari_TR

Page 17: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Some Language Issues and an Interface.

We now have to begin an implementation: we want to keep the implementation details as far from the user as possible, while accepting the limitations that the implementation language imposes on us.

For example: a C function does NOT return multiple values, so our Remove must reflect that.

Since we want to make sure that the queue or stack are properly updated on both insertion and removal, we will pass them as reference parameters in both cases. The item to be inserted can be passed by value (question: how big is this item going to be? can we afford an extra copy of it around the system?), while that to be removed must be passed by reference.

Page 18: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* StackInt.h */

#include “StackTyp.h” /* user must define */

extern void InitializeStack(Stack *S);

extern bool EmptyStack(Stack *S);

extern bool FullStack(Stack *S);

extern void Push(ItemType X, Stack *S);

extern void Pop(Stack *S, ItemType *X);

/* ------------------------------------------------- */

Note: for stacks, insertion is Push and removal is Pop. These have been "the names" for 40+ years, and you will not change them….

Page 19: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

You may also note another implementation decision:

For efficiency (to avoid unnecessary copying) and consistency, all functions expect the Stack to be passed by reference: only an address needs to be copied, and the user does not need to remember which function wants what …

The downside is that a malicious programmer could have introduced code to modify the information during the operations that should have been safe… (or YOU made a mistake in your code…).

SO: don't leave information OPEN unless you have no real choice… (don’t pass by reference what you could pass by value - it's more expensive but safer.)

Page 20: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* QueueInt.h */

#include “QueueTyp.h” /* user must define */

extern void InitializeQueue(Queue *Q);

extern bool EmptyQueue(Queue *Q);

extern bool FullQueue(Queue *Q);

extern void Insert(ItemType R, Queue *Q);

extern void Remove(Queue *Q, ItemType *F);

/* ------------------------------------------------- */

Note: Insert is sometimes called Enqueue, while Remove is Dequeue or Serve. Be warned.

Page 21: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Stack Example: LISP parenthesis matcher.

LISP (Lots of Irrelevant Superfluous Parentheses - actually LISt Processor, but that’s another story) has a very simple syntax: ANY function call has the form

(function_name parameter1 parameter2 … parameterN),

Where parameteri can be another expression of the same type.

For example, we define the factorial function:

(defun factorial (n)

(cond ((<= n 0) 1)

(T (* n (factorial (- n 1))))))

Page 22: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

It should be obvious that keeping all those parentheses straight is a problem for most human beings…

Some dialects of LISP (the old FranzLisp from Berkeley) allowed a user to finish a function definition with a "]", effectively telling the system to fill-in for her; other dialects of LISP do not object to having too many closing parentheses - they will give a warning and you might end up with nasty errors anyway, but, "anything to make the user happy", right?

Let’s modify the textbook’s program for parenthesis matching.

Page 23: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "StackInt.h"

bool Match(char c, char d)

{

switch(c) {

case '(' : return ((d == ')')||(d == ']'));

break;

default: return(false);

break;

}

}

Page 24: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

int ParenMatch(char d, Stack *S){ char c;

if (d == '(') { Push(d, S); return(0);// push it} else if (d == ')') { if (EmptyStack(S)) return(2);// too many closing ps else {

Pop(S, &c);if (!Match(c, d)) return(-1);// something wrongelse return(1); // normal return

}} else if (d == ']') {

while (!EmptyStack(S)) {Pop(S, &c);if (!Match(c, d))

return(-1); // there is something wrong}return(3); // did her a favor

} else return(1); // OK}

Page 25: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

int main(void){ int returnCode; Stack ParenStack;

char InputChar; // one character at a timeInitializeStack(&ParenStack);while ((InputChar = getchar()) != EOF) {

returnCode = ParenMatch(InputChar, &ParenStack);if (returnCode == -1) break;

} if (!StackEmpty(&ParenStack)) returnCode = 0;

switch (returnCode){ case -1 : printf("Error in parens.\n"); break; case 0 : printf("Too many open parens.\n"); break; case 1 : printf("It all appears OK.\n"); break; case 2 : printf("Too many closing ps.\n"); break; case 3 : printf("I fixed it for you.\n"); break;}

}

Page 26: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Linked Implementation of Stacks: the StackTyp.h file

#ifndef _STACKTYP_H#define _STACKTYP_H

typedef char ItemType;

typedef struct StackNodeTag { ItemType Item; struct StackNodeTag *Link;} StackNode;

typedef struct { StackNode *ItemList;} Stack;

#endif

Page 27: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

ItemList Item Link

Stack StackNode

Item

StackNode

Page 28: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

The StackInt.h file:

#include "StackTyp.h" /* user must define */

void InitializeStack(Stack *S);bool EmptyStack(Stack *S);bool FullStack(Stack *S);void Push(ItemType X, Stack *S);void Pop(Stack *S, ItemType *X);

Page 29: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

// StackImp.c#include "general.h"#include "StackInt.h"/* Local function prototypes */StackNode *MakeNode(ItemType);

// Push: make new node with item and push it onto stack;// Pre: the stack exists and has been initialized;// Post: item has been stored at the top of the stack.void Push(ItemType item, Stack *s){ StackNode *np = MakeNode(item); if (np == NULL) printf("Attempted to push a non-existing node.\n"); else { np->Link = s->ItemList; s->ItemList = np; }}

Page 30: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* Pop: pop a node from the stack and return its item. Pre: The stack exists and is not empty. Post: The item at the top of stack has been removed and returned in *item. */void Pop(Stack *s, ItemType *item){ StackNode *np;

if (s->ItemList == NULL) printf("Empty stack.\n"); else { np = s->ItemList; s->ItemList = np->Link; *item = np->Item; /* copy */ free(np); }}

Page 31: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* EmptyStack: return non-zero if stack is emptyPre: stack exists and has been initialized.Post: Return true if the stack is empty;

return false, otherwise. */

bool EmptyStack(Stack *s){ return (s->ItemList == NULL); }

/* FullStack: attempts to allocate the space for a node. Failure results in a false return.

Pre: stack exists and has been initialized.Post: Return true or false. */

bool FullStack(Stack *s){ StackNode *np; if ((np = malloc(sizeof(StackNode))) == NULL)

return (true); else { free(np); return (false); }}

Page 32: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* InitializeStack: initialize the stack to NULL. Pre: A Stack data structure exists - unknown state. Post: The stack has been initialized to be empty. */void InitializeStack(Stack *s){ s->ItemList = NULL;}

/* MakeNode: make a new node and insert item.Pre: None.Post: A new node with "item" in it exists. */

StackNode *MakeNode(ItemType item){ StackNode *np;

if ((np = malloc(sizeof(StackNode))) == NULL) printf("Exhausted memory.\n"); else { np->Item = item; np->Link = NULL; } return np;}

Page 33: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Stacks and Function Calls.

The first programming languages provided a mechanism for function call that involved saving the “return address” at some location of the code portion of the function, as well as saving any parameters and local variables in the same way. This meant that a function could not call itself. Why?

1) The initial caller calls the function and

a) saves the return address - call it A1 - in the function’s code section at address, say, raF ;

b) loads the parameters - call them P1 - in the function’s code section at address, say, pF.

Page 34: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

2) The called function sets up local variables in its own code section at address, say, lvF - and proceeds with execution.

There are now two possibilities:

A) the function terminates without calling itself either directly or indirectly (by calling some other function that calls IT). In this case, control returns to the caller, the right values are returned and put in the right memory locations and processing continues.

B) The function calls itself before terminating.

This is where the problems start...

Function code A1 Other: Local Vars, etc P1Function code area

Page 35: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Let’s say that it calls itself at address A2 of its own code section. It then saves this address in location raF (which is part of its own code section), loads the new parameters, etc…

The new copy of the function sets up local variables, etc. It then executes and, say, returns. It MUST return to A2, within its own code section, and completes executing again. Since the only return address it has is A2, it must now execute from that location on, … forever - this assumes that none of the computations result in some kind of fatal error…

Function code A2 Other: Local Vars, etc P2Function code area

Page 36: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Since recursion IS a very powerful technique to describe computational processes, it’s quite clear that this state of affairs is not really acceptable. What does one do?

The word STACK comes, miraculously, to mind.

Page 37: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

variables is now kept SEPARATE from the function code, in a data structure called an “activation frame”. When a function is called by somebody, a frame is created, this information is loaded into it and the frame is pushed onto a stack - the “activation stack”.

Param. ValueReturn Address

Pointer to Prev. Frame

Return Value

Calling Environment

Space for Local Vars.

Let’s now see what happens...

1) The initial caller calls the function and

a) creates an activation frame

b) saves the return address in the frame ;

c) loads the parameters in the frame.

Each function still has its code section in memory. The information about return address, parameters and local

Page 38: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

There are now two possibilities:

A) the function terminates without calling itself either directly or indirectly (by calling some other function that calls IT). In this case, control returns to the caller, the right values are returned and put in the right memory locations, the stack frame is popped from the activation stack and processing continues.

Param. ValueReturn Address

Pointer to Prev. Frame

Return Value

Calling Environment

Local Vars

Calling Environment

2) The called function sets up local variables in the frame - and proceeds with execution.

Somewhere along these steps the frame was pushed on the activation stack.

Page 39: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

B) The function calls itself before terminating:

a) creates an activation frame

b) saves the return address in the frame;

c) loads the parameters in the frame;

d) the called function sets up local variables in the frame - and proceeds with execution.

Somewhere along these steps the frame was pushed on the activation stack.

Param. ValueReturn Address

Pointer to Prev. Frame

Return Value

Calling Environment

Local Vars

Param. ValueReturn Address

Pointer to Prev. Frame

Return Value

Local Vars

Page 40: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

The function then executes and, say, returns. It MUST return to its own code section, the activation frame for the execution just completed is popped from the stack, and the function completes executing again.

The current stack frame has the CORRECT return address, so the function returns to the original caller.

Problem solved.

91.102 - Computing II

Param. ValueReturn Address

Pointer to Prev. Frame

Return Value

Calling Environment

Local Vars

Calling Environment

Page 41: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

There are some details that may not be completely clear - like who is really responsible for doing what when - but the framework will obviously work.

Since there is no such thing as a free lunch, what have we traded? Some time (frame allocation and stack management), and some space (the stack of frames) plus some complication in the code that must be generated by the compiler and the services that must be provided by the operating system. Also, the stack frames need not be of uniform size, so pushing and popping may require a bit more information saved in the frame itself (like where the previous one begins).

Page 42: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

CRUCIAL: we have “lost” control of space, since any number of activation frames could be created. At a time when memory was VERY expensive and scarce, this was not tolerable.

Ex.: in 1970, the Environmental Protection Agency of the City of New York (they took care of all the garbage for 8+ million people) did its payroll on a 4KiloWord (about 16KB) machine… EVERY BIT had to count… and one guy, with an unusual contract, didn't fit and had to be done by hand!!!

The payroll program was all coded in IBM Assembly Language.

91.102 - Computing II

Page 43: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Some more ideas about Queues.

A picture about linked representations: removal is easy but insertion is expensive (in time). Solution: give up some space (one more pointer).

F

F R

Easy but slow insertion (at end).

More space but faster insertion (at end).

Page 44: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Although many queues have no particular requirements about maximum size, there are a number of situations where this requirement is important. This means, in those cases, that an appropriate implementation of the queue will use arrays.

0 1 2 3 4 5 6 7 8 9 10111213141516Full Empty

Insertion0 1 2 3 4 5 6 7 8 9 10111213141516

Deletion0 1 2 3 4 5 6 7 8 9 10111213141516

Move everybody one position forward EVERY TIME you DELETE? - There must be a better way...

Page 45: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Circular Queues: use of the % (or mod, or remainder) operation.

0

1

2

34

5

6

7

0 % 8 = 0, …, 7 % 8 = 7, (7+1) % 8 = 0,

(7+2) % 8 = 1, ...

Page 46: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* ----------< begin file "QueueTyp.h" >---------- */ #ifndef _QUETYP_H #define _QUETYP_H #define MAXQUEUESIZE 100;

typedef arbitrary ItemType; // ItemType can be arbitrary.

typedef struct { int Count; /* number of queue items */ int Front; int Rear; ItemType Items[MAXQUEUESIZE]; } Queue; #endif // _QUETYP_H/* -----------< end file "QueueTyp.h" >----------- */

Page 47: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* ------< begin file "QueueImp.c" >------ */

#include <stdio.h> #include <stdlib.h> #include "QueueInt.h" /* the file "QueueInt.h" includes the file "QueueTyp.h" defined on previous slide.*//* -------------------- */

void InitializeQueue(Queue *Q) { Q->Count = 0;// Count == number of items in queue Q->Front = 0;// Front == loc. of item to remove next Q->Rear = 0; // Rear == place to insert next item }

Page 48: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

/* -------------------- */

bool Empty(Queue *Q) { return ( Q->Count == 0 ); }

/* -------------------- */

bool Full(Queue *Q) { return (Q->Count == MAXQUEUESIZE); }

91.102 - Computing II

Page 49: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

/* -------------------- */void Insert(ItemType R, Queue *Q){ if (Q->Count == MAXQUEUESIZE) { SystemError("attempt to insert into a full Queue"); } else { Q->Items[Q->Rear] = R; Q->Rear = (Q->Rear + 1) % MAXQUEUESIZE; ++(Q->Count); }}

/* -------------------- */void Remove(Queue *Q, ItemType *F){ if (Q->Count == 0) { SystemError("attempt to remove from empty Queue"); } else { *F = Q->Items[Q->Front]; Q->Front = (Q->Front + 1) % MAXQUEUESIZE; --(Q->Count); }}

Page 50: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

An Application of Queues: Simulation.

There are many situations where you may want to try something, but nobody will let you try it "for real". That usually means that trying it out "for real" is either too expensive or too dangerous - or both.

Q: How can you "try it out" cheaply and safely?

A: Build a simulator.

Page 51: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

A simulator - for us at least - is a computer program that attempts to capture all the relevant aspects of your proposed experiment, and has none of the costs (or dangers) of "doing it for real". Once the simulation runs have shown that the behavior you claim does occur, and that no problems arise, you MAY be allowed to move on to reality… Think of it as starting with a set of "training wheels".

91.102 - Computing II

Page 52: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

A Simple Airport Simulation: One Runway; one Take-Off queue; one Landing Queue.

Would you let yourself do this "for real", with real planes and real people in them?

The "unit of time" is the time period in which a plane can either take off or land. One Runway means that you cannot land one plane at the same time that another is taking off.

Planes arrive randomly according to some statistical law and are queued until they can land.

Planes want to depart randomly, according to a similar statistical law, and they are queued until they can take off.

Page 53: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

This program simulates an airport with only one runway.One plane can land or depart in each unit of time.Up to 5 planes can be waiting to land or take off at any time.How many units of time will the simulation run? 15Expected number of arrivals per unit time (real number)? 0.495Expected number of departures per unit time? 0.495 1 : Runway is idle. Plane 1 ready to take off. 2 : Plane 1 took off; in queue 0 units. 3 : Runway is idle. 4 : Runway is idle. Plane 2 ready to land. 5 : Plane 2 landed; in queue 0 units. 6 : Runway is idle. 7 : Runway is idle. Plane 3 ready to land. Plane 4 ready to take off. 8 : Plane 3 landed; in queue 0 units. 9 : Plane 4 took off; in queue 1 units. Plane 5 ready to land. Plane 6 ready to take off. 10 : Plane 5 landed; in queue 0 units. 11 : Plane 6 took off; in queue 1 units. Plane 7 ready to land. 12 : Plane 7 landed; in queue 0 units. Plane 8 ready to take off. 13 : Plane 8 took off; in queue 0 units. 14 : Runway is idle. Plane 9 ready to take off. 15 : Plane 9 took off; in queue 0 units.Simulation has concluded after 15 units.

91.102 - Computing II

Page 54: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

Total number of planes processed: 9 Number of planes landed: 4 Number of planes taken off: 5 Number of planes refused use: 0 Number left ready to land: 0 Number left ready to take off: 0 Percentage of time runway idle: 40.00 Average wait time to land: 0.00 Average wait time to take off: 0.40

Simulation code in ~giam/91.102/source/airport

Compile: g++ airport.c airsupport.c common.c queueC.c

Run: a.out

91.102 - Computing II

Page 55: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

The Readers and Writers problem.There are usually fewer printers than students

trying to get a printout (this problem was more common in the past, when one printer would have served the whole university). How do you make sure that the print jobs don't interfere with one another?

By setting up a queue: anybody can add a job to the queue (we need to make sure that distinct jobs will not try to occupy the same queue position - so only one student at a time can add a print job to the queue), while only the printer manager can take jobs OFF the queue.

The same mechanism (adding the restriction that only ONE print manager at a time can remove a job from the queue) can be used if you have multiple printers.

Page 56: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

The Web: you go to your favorite site and find that the page (or file) you want to see (or download) is taking a lot more time than the link you are paying for would require… What went wrong?

a) Too many people trying to get the server to serve… Your request gets queued - receives some service - gets queued again - receives some more service - etc…

b) Your server responds quickly and sends you the first packet. The packet gets to the first switch on the backward path and finds that the whole world is trying to send packets through that switch. Wait at the switch (queue) - or the switch has no more room to queue your packet: throw it away. Your program times out, sends another request, same junk...

Page 57: 91.102 - Computing II Abstract Data Types: Queues and Stacks. Implementation: Queues and Stacks. Applications of Queues and Stacks. The order in which

91.102 - Computing II

Some ideas about safety:

You may have noticed that many of the insertion and deletion functions PRINT some kind of message (and maybe terminate execution of the program) when they cannot complete (and they are of type void). This is not a great idea if you plan to create modules that would be used by others, because you have no idea of how the user needs to react to various errors.

A better solution is (if at all possible) to have each function return a code: the calling program checks the codes and takes appropriate action. The package user who calls the function without checking the code has only himself to blame if his program dies a messy (and possibly very expensive) death...