Abstract Data Types and Stacks CSE 2320 – Algorithms and Data Structures Vassilis Athitsos University of Texas at Arlington 1
Abstract Datatypes (ADT) ADT (Abstract Data Type) – is a data type (a set of values and a collection of operations on those values) that can only be accessed through an interface. Client is a program that uses an ADT. – E.g.: walmart.c – Will have: #include “list.h” Implementation is a program that specifies the data type and the operations for it. – E.g.: list.c – Function definitions and struct definitions (or class definitions) Interface a list of operations available for that datatype. – E.g.: list.h (notice, a header file, not a c file) – It will contain headers of functions and typedef for data types, – It is opaque: the client can not see the implementation through the interface.
Generalized Queues A generalized queue is an abstract data type that stores a set of objects. – Let's use Item to denote the data type of each object. The fundamental operations that such a queue must support are: void insert(Queue q, Item x): adds object x to set q. Item delete(Queue q): choose an object x, remove that object from q, and return it to the calling function. 3
Generalized Queues Basic operations: – void insert(Queue q, Item x) – Item delete(Queue q) The meaning of insert is clear in all cases: we want to add an item to an existing set. However, we note that delete does NOT take as an argument the item we want to delete, so the function itself must choose. 4
Generalized Queues - Delete How can delete choose which item to delete? – Choose the item that was inserted last. – Choose the item that was inserted first. – Choose a random item. – If each item contains a key field: remove the item whose key is the smallest. You may be surprised as you find out, in this course, how important this issue is. We will spend significant time studying solutions corresponding to different choices. 5
The Pushdown Stack The pushdown stack behaves like the desk of a busy (and disorganized) professor. – Work piles up in a stack. – Whenever the professor has time, he picks up whatever is on top and deals with it. We call this model a LIFO (last-in, first-out) queue. – The object that leaves the stack is always the object that was inserted last (among all objects still in the stack). Most of the times, instead of saying "pushdown stack" we simply say "stack". – By default, a "stack" is a pushdown stack. 6
Push and Pop The pushdown stack supports insert and delete as follows: – insert push: This is what we call the insert operation when we talk about pushdown stacks. It puts an item "on top of the stack". – delete pop: This is what we call the delete operation when we talk about pushdown stacks. It removes the item that was on top of the stack (the last item to be pushed, among all items still on the stack). 7
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop() 8 15
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop()
Examples of Push and Pop push(15) push(20) pop() – returns 20 push(30) push(7) push(25) pop() push(12) pop() 10 15
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() – returns 25 push(12) pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop() – returns 12 pop()
Examples of Push and Pop push(15) push(20) pop() push(30) push(7) push(25) pop() push(12) pop() pop() – returns
Uses of Stacks Modeling a busy professor's desk is NOT the killer app for stacks. Examples of important stack applications: 18
Uses of Stacks Modeling a busy professor's desk is NOT the killer app for stacks. Examples of important stack applications: – Function execution in computer programs: when a function is called, it enters the calling stack. The function that leaves the calling stack is always the last one that entered (among functions still in the stack). – Interpretation and evaluation of symbolic expressions: stacks are used to evaluate things like (5+2)*(12-3), or to parse C code (as a first step in the compilation process). – Search methods. Search is a fundamental algorithmic topic, with applications in navigation, game playing, problem solving… We will see more later in the course. 19
The Stack Interface (Textbook Version) The textbook defines a stack interface that supports four specific functions: void STACKinit(int max_size): – Initialize the stack. Argument max_size declares the maximum possible size for the stack. int STACKempty(): – Returns 1 if the stack is empty, 0 otherwise. void STACKpush(Item item): – Pushes the item on top of the stack. Item STACKpop(): – Removes from the stack the item that was on top, and returns that item. 20
Problems With Textbook Interface? 21
Problems With Textbook Interface? These functions do not refer to any specific stack object. What is the consequence of that? 22
Problems With Textbook Interface? These functions do not refer to any specific stack object. What is the consequence of that? – This interface can only support a single stack. If we need to use simultaneously two or more stacks, we need to extend the interface. In our implementation, we will pass the stack as an argument. 23
Implementing Stacks A stack can be implemented using: – lists or – arrays Both implementations are fairly straightforward. 24
List-based Stacks List-based implementation: – What is a stack? A stack is essentially a list. – push(stack, item) How? : O(??) – pop(stack) How? : O(??) 25
List-based Stacks List-based implementation: – What is a stack? A stack is essentially a list. – push(stack, item) How? : O(1) – ideally !!!! (frequent operation for this data structure) – pop(stack) How? : O(1) – ideally !!!! (frequent operation for this data structure) What type of insert and remove are fast for lists? – How many ‘ways’ can we insert in a list? 26 NULL …
List-based Stacks List-based implementation: – What is a stack? A stack is essentially a list. – push(stack, item) How? : inserts that item at the beginning of the list. O(1) – pop(stack) How? : removes (and returns) the item at the beginning of the list. O(1) 27 NULL …
Implementation Code See files posted on course website: – stack.h: defines the public interface. – stack_list.cpp: defines stacks using lists. – stack_array.cpp: defines stacks using arrays. – Note that these files must be compiled with g++: Use stack_lists.cpp g++ -o stacks stack_client.cpp stack_list.cpp list.c Use stack_arrays.cpp g++ -o stacks stack_client.cpp stack_array.cpp 28
The Stack Interface See file stack.h posted on the course website. ??? newStack(???); // this will be a bit tricky ??? destroyStack(???); ??? push(stack s, int content); ??? pop(stack s); ??? isStackEmpty(???); 29
The Stack Interface See file stack.h posted on the course website. stack newStack(); // this will be a bit tricky void destroyStack(stack s); void push(stack s, int content); int pop(stack s); //NOTE: type int, not link int isStackEmpty(stack s); 30
Defining Stacks typedef struct stack_struct * stack; struct stack_struct { ???; }; 31
Defining Stacks typedef struct stack_struct * stack; struct stack_struct { list items; }; 32 NULL … items Stack object
Creating a New Stack typedef struct stack_struct * stack; struct stack_struct { list items; }; stack newStack() { ??? } 33
Creating a New Stack typedef struct stack_struct * stack; struct stack_struct { list items; }; stack newStack() { stack result = malloc(sizeof(*result)); result->items = newList(); //mem alloc return result; } 34
Destroying a Stack typedef struct stack_struct * stack; struct stack_struct { list items; }; void destroyStack(stack s) { ??? } 35
Destroying a Stack typedef struct stack_struct * stack; struct stack_struct { list items; }; void destroyStack(stack s) { destroyList(s->items); free(s); } 36
Pushing an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; void push(stack s, int content) { ??? } 37
Pushing an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; void push(stack s, int content) { link L = newLink(content); insertAtBeginning(s->items, L); } 38
Popping an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; int pop(stack s) { ??? } 39
Popping an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; int * pop(stack s) { link top = removeFirst(s->items); return linkItem(top); } 40 What is wrong with this definition of pop?
Popping an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; int * pop(stack s) { link top = removeFirst(s->items); return linkItem(top); } 41 What is wrong with this definition of pop? Memory leak!!!
Popping an Item typedef struct stack_struct * stack; struct stack_struct { list items; }; int pop(stack s) { if (isStackEmpty(s)) ERROR!!! link top = removeFirst(s->items); int item = linkItem(top); free(top); return item; } 42
WHY use a Stack ADT? Why should we have a Stack interface, when all we do is use list operations? Why not use a list directly? – Protection: from performing unwanted ops (e.g. an insert at a random position in the list) – Flexibility: To modify the current implementation To use another stack implementation – Isolates the dependency of the Stack implementation on the list interface: if the list INTERFACE (.h file) is modified we will only need to go and change the STACK implementation (.c file), not all the lines of code when a stack operation is done in all the client programs. – It makes the stack behavior explicit: what we can do and we can not do with a stack. 43
Array-Based Implementation of Stacks 44
Array-based Stacks Array-based implementation: – What is a stack? What will hold the data of the stack? – push(stack, item) How? : O(1) - can we get this? – pop(stack) How? : O(1) - can we get this? 45
Array-based Stacks Array-based implementation: – What is a stack? What will hold the data of the stack? An array. – push(stack, item) How? : ‘insert’ at the end of the array. O(1) - Yes – pop(stack) How? : ‘remove’ from the end of the array. O(1) - Yes See stack_array.cpp 46
Array-based Stacks max_size -1 0 top index
Array-based Stacks max_size top index push(5) 5
Array-based Stacks max_size top index push(5) push(8) 5 8
Array-based Stacks max_size top index push(5) push(8) push(20)
Array-based Stacks max_size top index push(5) push(8) push(20) pop() 5 8
Defining Stacks Using Arrays typedef struct stack_struct * stack; struct stack_struct { int max_size; int top; int* items; };
Creating a New Stack struct stack_struct { int* items; int top; int max_size; }; stack newStack(???) { ??? } 53
Creating a New Stack struct stack_struct { int* items; int top; int max_size; }; stack newStack(int max_size) { stack result = (stack)malloc(sizeof(*result)); result->items = (int*)malloc(max_size * sizeof(int)); result->max_size = max_size; result->top = -1; return result; } 54
Destroying a Stack struct stack_struct { int* items; int top; int max_size; }; void destroyStack(stack s) { ??? } 55
Destroying a Stack struct stack_struct { int* items; int top; int max_size; }; void destroyStack(stack s) { free(s->items); free(s); } 56
Pushing an Item struct stack_struct { int* items; int top; int max_size; }; void push(stack s, int data) { ??? } 57
Pushing an Item struct stack_struct { int* items; int top; int max_size; }; void push(stack s, int data) { if (s->top == s->max_size - 1) ERROR!!! s->top = s->top + 1; s->items[s->top] = data; } 58
Popping an Item struct stack_struct { int* items; int top; int max_size; }; ??? pop(stack s) { ??? } 59
Popping an Item struct stack_struct { int* items; int top; int max_size; }; int pop(stack s) { if (isStackEmpty(s)) ERROR!!! int item = s->items[s->top_index]; s->top = s->top - 1; return item; } 60