310 likes | 396 Views
Today’s Agenda. Access Restricted Lists Stacks, Queues and their applications. ADT Stack – Type Definition. /* file: stack.h */ #include “element.h” struct _stacknode; typedef struct _stacknode *StackNode; struct _stacknode { Element e; StackNode next; }; typedef struct {
E N D
Today’s Agenda Access Restricted Lists Stacks, Queues and their applications. Sundar B. BITS, Pilani.
ADT Stack – Type Definition /* file: stack.h */ #include “element.h” struct _stacknode; typedef struct _stacknode *StackNode; struct _stacknode { Element e; StackNode next; }; typedef struct { StackNode top; unsigned int size; Boolean error; } Stack;
ADT Stack - Implementation /* file: stackOps.c */ #include “stack.h” #include “element.h” #include “stdlib.h” Stack createStack() { Stack s; s.top = NULL; s.size = 0; s.error = FALSE; return s; } Boolean isEmpty(Stack s) { return (top==NULL) ? TRUE : FALSE; } Element top(Stack s) { return s.top->e; }
s1.top = (StackNode)malloc(sizeof(struct __stacknode)); if (s1.top == NULL) { s1.error = TRUE; // “out of memory” error return s1; } s1.top->e = e ; // copy element s1.top->next = s.top; s1.size = s.size+1; ADT Stack - Implementation /* file: stackOps.c */ Stack push(Element e, Stack s) { Stack s1; return s1; // Can we change s and return it? } // Why not pass address of s instead of returning?
s1.top = s.top->next ; // skip element s1.size = s.size-1; temp = s.top ; ADT Stack – Implementation /* file: stackOps.c */ Stack pop(Stack s) { Stack s1; StackNode temp; return s1; } free(temp); // if the original Stack can be destroyed
Use of ADT Stack - Example • Problem: • Consider a string of parentheses: • ()()(((()))) • Is this a valid string? • Define a string of parentheses to be valid if: • Each Open ‘(‘ has a matching Close ‘)’ and the Open always appears before the Close • Valid instances: • ()()() • ((()))(()) • Invalid instances: • (() • )()( Sundar B. BITS, Pilani.
Use of ADT Stack - Example • Design an algorithm to verify whether a string of parentheses is valid. • Idea • Push each Open onto a stack; Pop an Open for each Close. • The string is valid • If the stack is empty at the end • The string is invalid: • If stack is non-empty at the end (i.e when the string is empty) OR • If stack is empty before the end (i.e when the string is non-empty)
Use of ADT Stack - Example • The parentheses problem does have an alternative solution. • Observation: • In a valid string count of Opens equals the count of Closes. • But )( is an invalid string with equal count of Opens and Closes. • In a valid string the count of Opens of any prefix is greater than or equal to the count of Closes. • This is is not so for invalid strings. Sundar B. BITS, Pilani.
Use of ADT Stack - Example • Alternative solution: • Count the ‘Open’s and the ‘Close’s separately. • If at any time, you have more Closes than Opens, then the string is invalid. • If at the end the counts match, then the string is valid. • So, let us complicate the problem • The string may have parentheses, square brackets, as well as braces, for instance: • {[]()((()))} Sundar B. BITS, Pilani.
Use of ADT Stack - Example • New definition of validity: • Each Open(t) must have a matching Close(t) where t is one of PAREN, SQUA or BRACE. • An Open(t) must appear before the corresponding Close(t) • But these two conditions may be not be enough: • Is ([)] valid? • All ‘Opens’, inside an Open(t) and its corresponding Close(t), must be closed. Sundar B. BITS, Pilani.
Use of ADT Stack - Example • Counting solution will not work for verifying (new) validity of string. • But the stack solution works - with a minor change: • Push each Open(t) onto stack • For each Close(t) pop an Open(t) – i.e. an Open of the same kind. Sundar B. BITS, Pilani.
Use of ADT Stack - Example Algorithm Match(charSeq) // charSeq is a sequence of bracketing characters // Let stk be a Stack (initially empty). while (!isEmpty(charSeq)) { b = nextChar(charSeq); if (isOpen(b)) { stk = push(b, stk); } else if (isClose(b)) { if (isEmpty(stk) || (b.kind == top(stk).kind)) { return FALSE; } else {stk = pop(stk);} } } return isEmpty(stk);
Use of ADT Stack - Example • Well that was fun , but of what use is solving the problem? • This is a common problem in editors – text editors (such as vi), or program editors (such as Turbo-C or others). • Exercise: • Complete the implementation. • A type for bracket chars is needed – with two pieces of info.: kind (PAREN, SQUA, or BRACE) and end (OPEN, or CLOSE) Sundar B. BITS, Pilani.
Variant of the Example • In a real editor – say vi – matching bracket characters have to be done while the user is typing. • i.e two different things can happen at the time: • The user inputs characters and • The program matches them • Usually there is a speed mismatch: • A buffer is needed in such situations. Sundar B. BITS, Pilani.
Variant of the Example • The program gets the next character from the buffer – • one at a time instead of assuming the whole string is available. • The user inserts characters one at a time. • Insertion and deletion happen at different ends of the same list (that we call buffer) • This is a different kind of access-restricted list: • It is sequential. • It is First-In-First-Out (FIFO) • Addition is done at one end and deletion at the other end. Sundar B. BITS, Pilani.
Access-restricted lists: Queues • These kind of lists are called queues: • They are useful in many situations where there is a speed mismatch: • A service and more than one client – arrival rate (of clients) does not match with the service rate. • E.g. Ticket Counters • A producer and consumer operating at different speeds • E.g. Input devices and programs; • Programs and output devices Sundar B. BITS, Pilani.
Use of Stack & Queue - Example Algorithm Match(charSeq) // charSeq is a QUEUE of bracketing characters // Let stk be a Stack (initially empty). while (!isEmptyQ(charSeq)) { b = next(charSeq); charSeq = delete(charSeq); if (isOpen(b)) { stk = push(b, stk); } else if (isClose(b)) { if (isEmpty(stk) || (b.kind == top(stk).kind)) { return FALSE; } else {stk = pop(stk);} } } return isEmpty(stk);
Use of Stack & Queue - Example • In the previous slide, the algo. Assumes the whole seq. is available in the queue (Or the input speed is higher than processing speed). • If this is not the case modify the algo: • Check for end of string (some special char.) • If queue is empty then wait; when queue becomes non-empty then restart. • This cannot be directly implemented in C – because two processes (user and editor) have to running at the same time. Sundar B. BITS, Pilani.
ADT Queue • Operations: • createQ returns a new (empty) Queue • addQ adds an Element to (the rear of a) Queue • isEmptyQ checks whether a Queue is empty • frontQ returns the Element at the front of a Queue • deleteQ deletes the Element at the front of a Queue Sundar B. BITS, Pilani.
ADT Queue – Interfaces /* file: queueOps.h */ #include “boolean.h” #include “element.h” #include “queue.h” /* Create an empty Queue */ /* Post-condition: return q such that isEmptyQ(q) = TRUE */ Queue createQ(); /* Post-condition: return TRUE if q is empty FALSE otherwise */ Boolean isEmptyQ(Queue q); Sundar B. BITS, Pilani.
ADT Queue - Interfaces /* file: queueOps.h */ /* Add an Element to a Queue */ /* Post-condition: return q1 such that isEmptyQ(q1) is FALSE AND sizeQ(q1) = sizeQ(q) + 1 AND addQ and deleteQ satisfy FIFO property */ Queue addQ(Element e, Queue q); /* Get the front Element of a Queue */ /* Pre-condition: isEmptyQ(q) is FALSE */ Element frontQ(Queue q); Sundar B. BITS, Pilani.
ADT Queue - Interfaces /* file: queueOps.h */ /* Delete an Element from the front of Queue */ /* Pre-condition: isEmptyQ(q) is FALSE Post-condition: return q1 such that sizeQ(q1) = sizeQ(q) - 1 AND addQ and deleteQ satisfy FIFO property */ Queue deleteQ(Queue q); /* Post-condition: return the size of the queue */ int sizeQ(Queue q); Sundar B. BITS, Pilani.
ADT Queue - Types /* file: queue.h */ #include “qnode.h” typedef struct { QNode front; QNode rear; unsigned int size; Boolean error; } Queue; Sundar B. BITS, Pilani.
ADT Queue - Implementation • Represent a Queue as a linked list. • Addition creates a new node in the rear • Deletion deletes the first node • Front returns the contents of the first node Sundar B. BITS, Pilani.
ADT Queue – Node Type Definition /* file: qnode.h */ #include “element.h” struct __qnode; typedef struct __qnode *QNode; struct __qnode { Element e; QNode next; }; Sundar B. BITS, Pilani.
ADT Queue - Implementation /* file: queueOps.c */ #include “boolean.h” #include “element.h” #include “queue.h” #include <stdlib.h> Queue createQ() { Queue q; q.front = q.rear = NULL; q.size = 0; q.error = FALSE; } Boolean isEmptyQ(Queue q) { return q.front == NULL; } Sundar B. BITS, Pilani.
q1.rear = (QNode)malloc(sizeof(struct __qnode)); if (q1.rear == NULL) { q1.error = TRUE; return q1; } q1.rear->e = e; // copy element q1.rear->next = NULL; // Will the following work if q is empty? q.rear->next = q1.rear; q1.size = q.size+1; q1.front = q.front; ADT Queue - Implementation /* file: queueOps.c */ Queue addQ(Element e, Queue q) { Queue q1; return q1; } Sundar B. BITS, Pilani.
// Will the following work if q is a singleton? q1.front = q.front->next; q1.rear = q.rear; q1.size = q.size-1; free(q.front); ADT Queue - Implementation /* file: queueOps.c */ Queue deleteQ(Queue q) { Queue q1; return q1; } Element frontQ(Queue q) { return q.front->e; } Sundar B. BITS, Pilani.
ADT Queue – Alternate Implementation • Exercise: • Implement ADT (Bounded) Queue using circular array implementation. • In particular, • How is isEmpty operation implemented? Sundar B. BITS, Pilani.
ADT Queue • Change in requirement (one or more of these): • Large (FIFO) list needed – not enough memory! • List must be persistent – must survive multiple runs of program • List to be exchanged between two programs • Files (in persistent storage) fit the bill • Indeed, files are sequential access lists – in particular, FIFO lists! • read is done at the front and write at the rear Sundar B. BITS, Pilani.
Files • All input and output use files (in Unix) • Keyboard input is stdin • Monitor output is stdout • stdin and stdout are files declared in stdio.h • stdio.h contains a type FILE and operations for opening, closing, reading and writing. Sundar B. BITS, Pilani.