You are on page 1of 110

This file has been cleaned of potential threats.

If you confirm that the file is coming from a trusted source, you can send
the following SHA-256 hash value to your admin for the original file.

e30d63709d403c1d52aff937082177bce39be888caa945951b82ada455d7c
12f
Abstract Data Types
Abstract Data Types
• A useful tool for specifying the logical properties of a data type
is the abstract data type, or ADT.

• A data type is a collection of


– data objects that share a defined set of properties and
– operations for processing the objects.

• That collection and those operations form a concept that may be


implemented using a particular hardware or software data
structure.
ADT
• Some programming language provide explicit mechanism to
support the distinction between specification and
implementation.
• C++, Java : a class
• C does not have an explicit mechanism for implementing
ADTs, but it is still possible and desirable to design your data
types using the same notion.
Example : lists, sets, graphs along with their operations
Why Abstract Data Types?

• User of the ADT “sees” only the interface to the objects; the
implementation details are “hidden” in the definition of the
ADT

• The user is constrained to manipulate the object solely


through the functions (operations) that are provided.

• The designer may still alter the representation as long as the


new implementations of the operations do not change the
user interface. This means that users will not have to recode
their algorithms.
ADT
The basic idea:
– the implementation of these operations is written
– any other part of the program that needs to perform some
operation on the ADT calls the appropriate function
– If implementation details change, it will be transparent to
the rest of the program.
Examples of ADTs
• String ADT
– definition of string object (alphabet, sequence)
– definition of string operations
• Boolean StringCopy (srcString, dstString)
• Boolean StringConcat (srcString, dstString)
• Boolean StringCompare (SrcString, dstString)
• Void StringPrint (String);
– possible implementations
• array implementation
• linked list implementation
• circular doubly-linked list implementation
ADT Example: Rational Numbers
• Rational numbers
– Can be written as a/b where a and b are int and b != 0
– Precision may be lost in representing as a single number
• A rational number has two parts : numerator and denominator – both are
integers.
• Interface functions
makerational
add
mul
equal
printrat
reduce
ADT: Rational Number
Interface functions

Constructor function:
RATIONAL makerational (int, int);
Selector functions :
int numerator (RATIONAL);
Int denominator (RATIONAL) ;
Operations:
RATIONAL add (RATIONAL,RATIONAL);
RATIONAL mult (RATIONAL, RATIONAL);
RATIONAL reduce (RATIONAL) ;
Equality testing :
int equal (RATIONAL, RATIONAL);
Print :
void printrat (RATIONAL) ;
Several Ways to Represent Rational

typedef struct {
int numerator;
int denominator;
} Rational;

typedef struct {
int ar[2];
} Rational;
ADT: Rational Number
Concrete implementation I

typedef struct { RATIONAL makerational (int x, int y) {


int numerator; RATIONAL r;
int denominator; r.numerator = x;
}RATIONAL; r.denominator = y;
return r;
}

RATIONAL reduce (RATIONAL r) {


int numerator (RATIONAL r) { int g;
return r.numerator; g = gcd(r.numerator,r.denominator);
} r.numerator /= g;
int denominator (RATIONAL r) { r.denominator /= g;
return r.denominator; return r;
} }
ADT: Rational Number
implementation of add (1)
typedef struct {
int numerator;
int denominator;
} RATIONAL;

RATIONAL add (RATIONAL r1, RATIONAL r2) {


RATIONAL r;
int g;
g = gcd(r1.denominator,r2.denominator);
r.denominator = lcm(r1.denominator,r2.denominator);
r.numerator = r1.denominator*r2.denominator/g;
r.numerator += r2.denominator*r1.numerator/g;
return r;
}
ADT: Rational Number
implementation of add (2)
typedef struct {
int numerator;
int denominator;
}RATIONAL;

RATIONAL add (RATIONAL r1, RATIONAL r2) {


RATIONAL r;
r.numerator = r1.numerator*r2.denominator
+r2.numerator*r1.denominator;
r.denominator=r1.denominator*r2.denominator;
return r;
}
ADT: Rational Number
Concrete implementation I
RATIONAL mult (RATIONAL r1, RATIONAL r2) {
typedef struct { RATIONAL r;
int numerator; r.numerator = r1.numerator*r2.numerator;
int denominator;
r.denominator = r1.denominator*r2.denominator;
}RATIONAL;
r = reduce (r);
return r;
}

int equal (RATIONAL r1, RATIONAL r2) {


return
(r1.numerator*r2.denominator==r2.numerator*r1.denominator);
}

void printrat (RATIONAL r) {


printf (“%d / %d “,r.numerator, r.denominator);
}
ADT: Rational Number
Concrete implementation II

typedef struct { RATIONAL makerational (int x, int y) {


int ar[2] ; RATIONAL r;
r.ar[0] = x;
}RATIONAL;
r.ar[1] = y;
return r;
}

RATIONAL reduce (RATIONAL r) {


int numerator (RATIONAL r) { int g;
return r.a[0]; g = gcd
} (r.numerator,r.denominator);
int denominator (RATIONAL r) { r.a[0] /= g;
return r.a[1]; r.a[1] /= g;
} return r;
}
The List ADT

• A list : <A1, A2, ... , AN> of size N.


• Special list of size 0 : an empty list
• Operations:
LIST makenull () : returns an empty list
LIST makelist (ETYPE) : makes a list containing a single
element
void printlist (LIST)
int search(ETYPE, LIST) : searches whether a key is in the list
void insert (ETYPE, LIST)
void delete (ETYPE, LIST)
ETYPE findKth (LIST)
Array Implementation of List
typedef int ETYPE;
typedef struct {
ETYPE elements[MAXS];
int size;
} LIST;
LIST makenull () ;
LIST makeList (ETYPE) ;
void printList (LIST) ;
int IsEmpty (LIST) ;
int search (ETYPE, LIST) ;
void delete (ETYPE, LIST * );
void insert (ETYPE, LIST * )
Complex Number ADT
typedef struct {
float real;
float imag;
} COMPLEX;

COMPLEX makecomplex (float, float) ;


COMPLEX addc (COMPLEX, COMPLEX);
COMPLEX subc (COMPLEX, COMPLEX);
COMPLEX multc (COMPLEX, COMPLEX);
COMPLEX divc (COMPLEX, COMPLEX);
SET ADT
Interface functions (1): Interface functions (2):

SET makenullset () ; SET makenullset () ;


int member (ETYPE, SET) ;
int member (ETYPE, SET) ;
void adjoin(ETYPE, SET *);
SET adjoin (ETYPE, SET); void union (SET, SET, SET*);
SET union (SET, SET) ; void intersection (SET, SET,
SET intersection (SET, SET); SET*);
void printset (SET) ; void printset (SET) ;
Concrete implementation of SET ADT

typedef struct {
ETYPE elem[MAX];
int size;
} SET;

Implementation 1 : sorted array


adjoin : Sorted insert
member : Binary search
delete : ?
union : merge 2 sorted arrays
intersection : ?
Concrete implementation of SET ADT
typedef struct {
ETYPE elem[MAX];
int size;
} SET;

Implementation 2 : unsorted array


keep the elements in the array unsorted.
adjoin : Insert at the end
member : Search till found or till the end
delete : Go through the array sequentially until
element is found, or reach the end.
Then left shift the array.
union , intersection ?
Concrete implementation of SET ADT
typedef struct node {
ETYPE elem;
struct node * next;
} * SET;

Implementation 3, 4 : linked list


Sorted or unsorted
adjoin :
member :
delete :
union , intersection
Another ADT Example: Stacks
• LIFO: Last-In, First-Out
• Like the stack of trays at the cafeteria
– “Push” a tray onto the stack
– “Pop” a tray off the stack
• Useful in many contexts
The Stack ADT
• Objects:
• a finite sequence of elements of the same type
• additions restricted to one end of the sequence called the top
of the stack
• deletions also restricted to the same end

• Operations
– initialize
– push
– pop
– empty
– full
Stack Properties and Attributes
Properties
1. LIFO data structures.
2. All accesses are done to the element referenced by top.
3. The top always refers to the topmost element in the stack.
4. Insertions are done “above” the top element.

Attributes
size : The number of elements in the stack: size >= 0 at all times.
top : The topmost element of the stack, refers to null, a special
value indicating top doesn’t reference anything in the stack.

6-24
Example 3 :: Last-In-First-Out STACK
Assume:: stack contains integer elements

void init (stack *s); /* Create a new stack */

void push (stack *s, int element);


/* Insert an element in the stack */
int pop (stack *s);
/* Remove and return the top element */
int isempty (stack *s);
/* Check if stack is empty */
int isfull (stack *s);
/* Check if stack is full */

Spring 2012 Programming and Data Structure 25


Contd.
• We shall look into two different ways of
implementing stack:
– Using arrays
– Using linked list

Spring 2012 Programming and Data Structure 26


Example:: First-In-First-Out QUEUE
Assume:: queue contains integer elements

void enqueue (queue *q, int element);


/* Insert an element in the queue */
int dequeue (queue *q);
/* Remove an element from the queue */
queue *create();
/* Create a new queue */
int isempty (queue *q);
/* Check if queue is empty */
int size (queue *q);
/* Return the no. of elements in queue */

Spring 2012 Programming and Data Structure 27


Stack Implementations: Using Array

Spring 2012 Programming and Data Structure 28


STACK USING ARRAY
PUSH

top

top

Spring 2012 Programming and Data Structure 29


STACK USING ARRAY
POP

top

top

Spring 2012 Programming and Data Structure 30


stack.h

#define SIZE 200


#define ERROR 1
#define OK 0
typedef struct {
int data[SIZE];
int tos;
} stack ;
void init(stack *) ;
int push(stack * , int) ;
int pop(stack *) ;
int top(stack *, int *) ;
int isEmpty(stack *) ;
int isFull(stack *) ;
stack.c
#include "stack.h"
int Pop(stack *s) {
void init(stack *s) {
if(isEmpty(s)) {
s->tos = -1;
printf("The STACK is empty\n");
}
return ERROR ;
int push(stack *s, int n) {
}
if(isFull(s)) {
s -> tos-- ;
printf("The STACK is full\n");
return OK ;
return ERROR ;
}
}
int isFull(stack *s) {
s->tos++;
return s->tos == SIZE-1;
s->data[s->tos]=n;
}
return OK ;
int isEmpty(stack *s) {
}
return s->tos == -1;
}
stack.c
int Top(stack *s , int *val) {
if (isEmpty(s)) {
printf("The STACK is empty\n") ;
return ERROR ;
}
*val = (s -> data[s -> tos]) ;
return OK ;
}
Array Implementation of Stack
CAPACITY too large: waste memory

data wasted space

CAPACITY too small:

data
Compiling the datatype
$ gcc -c stack.c

We get the object module stack.o. We can


construct library from it.
User Program: testStack.c
#include <stdio.h>
#include "stack.h"
int main() // testStack.c
{
stack s ;
int x , err , val ;
char c ;
init(&s);
printf(" ’U’ for push (U 15)\n ’O’ for pop\n ’T’ for top
printf(" ’E’ for exit :\n");
while((c = getchar()) != ’e’ && c != ’E’)
switch(c) {
case ’U’ : scanf("%d",&x);
err = push(&s,x);
break;
case ’O’ : err = pop(&s);
break;
case ’T’ : err = top(&s , &val) ;
if(!err) printf("%d\n", val);
break;
case ’\n’ : case ’\t’ : case ’ ’ : break;
default : printf("Token Unknown\n");
}
return 0;
}
Compiling the user program
• $ gcc -Wall testStack.c stack.o
• We get the executable module a.out.
Stack: Linked List Structure

PUSH OPERATION

top

Spring 2012 Programming and Data Structure 39


Stack: Linked List Structure

POP OPERATION

top

Spring 2012 Programming and Data Structure 40


Representation
struct stack {
int data ;
struct stack *next ;
};
typedef struct stackNode node, *stack ;
Interface functions (stackl.h)
#include <stdio.h>
#include <stdlib.h>
#define ERROR 1
#define OK 0
struct stack {
int data ;
struct stack *next ;
};
typedef struct stack node, *stack ;
#define INIT(s) ((s)=NULL)
#define ISEMPTY(s) ((s) == NULL)
int push(stack * , int) ;
int pop(stack *) ;
int top(stack, int *) ;
Implementation File: stackSR.c
#include "stackSR.h"
int push(stack *s, int n) { // stackSR.c
stack temp ;
temp=(stack)malloc(sizeof(node)) ;
if(temp == NULL) {
printf("The STACK is full\n");
return ERROR ;
}
temp->data=n;
temp->next=*s ;
*s = temp ;
return OK ;
}
stackSR.c continued
int pop(stack *s) {
stack temp ;
if(ISEMPTY(*s)) {
printf("The STACK is empty\n");
return ERROR ;
}
temp=*s;
*s=(*s)->next ;
free(temp) ;
return OK ;
}
stackSR.c continued
int top(stack s , int *val) {
if(ISEMPTY(s)) {
printf("The STACK is empty\n") ;
return ERROR ;
}
*val = s -> data ;
return OK ;
}
User Program: testStack.c
#include <stdio.h>
#include "stackSR.h"
int main() // testStackSR.c
{
stack s ;
int x , err , val ;
char c ;
INIT(s);
printf(" ’U’ for push (U 15)\n ’O’ for pop\n ’T’ for top
printf(" ’E’ for exit :\n");
while((c = getchar()) != ’e’ && c != ’E’)
switch(c) {
case ’U’ : scanf("%d",&x);
err = push(&s,x);
break;
case ’O’ : err = pop(&s);
break;
case ’T’ : err = top(s , &val) ;
if(!err) printf("%d\n", val);
break;
case ’\n’ :case ’\t’ :case ’ ’ : break;
default :printf("Token Unknown\n");
}
return 0;
}
Queue Implementation

Spring 2012 Programming and Data Structure 48


Figure 5-1

Queues in Our Life

• A queue is a FIFO structure: Fast In First Out


Circular Arrays 7 0

• Neat trick: use a circular array to insert and 6 1


remove items from a queue in constant
5 2
time
• The idea of a circular array is that the end of 4 3
the array “wraps around” to the start of the
array
Figure 5-16

Queue will overgrow the array

• Should we use VERY L A R G E ARRAYS?


Array implementation of queues

queueAry maxsize count front rear

7 4 1 5

front rear

11 37 22 15 3 -7 1
Queue on Circular Array: Representation

#define MAX 200


typedef struct {
int data[MAX] ;
int front , rear ;
} queue;
The queue may contain MAX - 1 data.
Queue on Circular Array: Operations

void init(queue *) ;
int add(queue *, int) ;
int delete(queue *);
int front(queue *, int *) ;
int isEmpty(queue *) ;
int isFull(queue *) ;
Interface File: queue.h
#include <stdio.h>
#define MAX 200
#define ERROR 1
#define OK 0
typedef struct {
int data[MAX];
int front, rear;
} queue;
/* Queue may contain MAX-1 data.*/
void init(queue *);
int add(queue *, int);
int delete(queue *);
int front(queue *, int *);
int isEmpty(queue *);
int isFull(queue *);
Implementation File: queue.c
#include "queue.h"
void init(queue *q) { q->front=q->rear=0; }
int isEmpty(queue *q)
{ return q->rear == q->front; }
int isFull(queue *q)
{ return (q->rear+1)%MAX == q->front; }
int add(queue *q, int n) {
if(isFull(q)) return ERROR;
q->rear=(q->rear+1)%MAX;
q->data[q->rear]=n;
return OK ;
}
int delete(queue *q) {
if(isEmpty(q)) return ERROR ;
q->front=(q->front+1)%MAX ;
return OK ;
}
int front(queue *q , int *v) {
if(isEmpty(q)) return ERROR ;
*v=q->data[(q->front+1)%MAX] ;
return OK ;
}
User Program: testQueue.c
#include "queue.h"
int main() {
queue q ;
int x , err , val ;
char c;
init(&q);
printf(" ’A’ for add (A 15)\n") ;
printf(" ’D’ for delete\n ’F’ for front\n ’E’ for exit
while((c = getchar()) != ’e’ && c != ’E’)
switch(c) {
case ’A’ : scanf("%d",&x);
err = add(&q,x);
if(err)
printf("Queue is full\n") ;
break;
case ’D’ : err = delete(&q);
if(err)
printf("Q empty\n") ;
break;
case ’F’ : err = front(&q , &val)
if(err) printf("Q empty\n") ;
else printf("%d\n",val);
break;
case ’\n’ :case ’\t’ :case ’ ’ :
break;
default : printf("Token Unknown\n");
}
return 0 ;
}
Basic Idea
– Create a linked list to which items would be added
to one end and deleted from the other end.
– Two pointers will be maintained:
• One pointing to the beginning of the list (point from
where elements will be deleted).
• Another pointing to the end of the list (point where
Rear
new elements will be inserted).

Front DELETION INSERTION


Spring 2012 Programming and Data Structure 63
QUEUE: LINKED LIST STRUCTURE

ENQUEUE

front rear

Spring 2012 Programming and Data Structure 64


QUEUE: LINKED LIST STRUCTURE

DEQUEUE

front rear

Spring 2012 Programming and Data Structure 65


QUEUE using Linked List
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node{
char name[30];
struct node *next;
};

typedef struct node _QNODE;

typedef struct {
_QNODE *queue_front, *queue_rear;
} _QUEUE;

Spring 2012 Programming and Data Structure 66


_QNODE *enqueue (_QUEUE *q, char x[]) {
_QNODE *temp;
temp= (_QNODE *)
malloc (sizeof(_QNODE));
if (temp==NULL){
printf(“Bad allocation \n");
return NULL;
}
strcpy(temp->name,x);
temp->next=NULL;
if (q->queue_rear==NULL) {
q->queue_rear=temp;
q->queue_front=q->queue_rear;
}
else {
q->queue_rear->next=temp;
q->queue_rear=temp;
}
return(q->queue_rear);
}
Spring 2012 Programming and Data Structure 67
char *dequeue(_QUEUE *q,char x[])
{
else{
_QNODE *temp_pnt;
strcpy(x,q->queue_front->name);
temp_pnt=q->queue_front;
if(q->queue_front==NULL){
q->queue_front=
q->queue_rear=NULL;
q->queue_front->next;
printf("Queue is empty \n");
free(temp_pnt);
return(NULL);
if(q->queue_front==NULL)
}
q->queue_rear=NULL;
return(x);
}
}

Spring 2012 Programming and Data Structure 68


void init_queue(_QUEUE *q)
{
q->queue_front= q->queue_rear=NULL;
}

int isEmpty(_QUEUE *q)


{
if(q==NULL) return 1;
else return 0;
}

Spring 2012 Programming and Data Structure 69


int main() {
int i,j;
char command[5],val[30];
_QUEUE q;

init_queue(&q);

command[0]='\0';
printf("For entering a name use 'enter <name>'\n");
printf("For deleting use 'delete' \n");
printf("To end the session use 'bye' \n");
while(strcmp(command,"bye")){
scanf("%s",command);

Spring 2012 Programming and Data Structure 70


if(!strcmp(command,"enter")) {
scanf("%s",val);
if((enqueue(&q,val)==NULL))
printf("No more pushing please \n");
else printf("Name entered %s \n",val);
}

if (!strcmp(command,"delete")) {
if (!isEmpty(&q))
printf("%s \n",dequeue(&q,val));
else printf("Name deleted %s \n",val);
}
} /* while */
printf("End session \n");
}

Spring 2012 Programming and Data Structure 71


Problem With Array Implementation

ENQUEUE DEQUEUE

Effective queuing storage area of array gets reduced.

0 N

front
front rearrear

Use of circular array indexing

Spring 2012 Programming and Data Structure 72


Queue: Example with Array Implementation
#define MAX_SIZE 100

typedef struct { char name[30];


} _ELEMENT;

typedef struct {
_ELEMENT q_elem[MAX_SIZE];
int rear;
int front;
int full,empty;
} _QUEUE;

Spring 2012 Programming and Data Structure 73


Queue Example: Contd.
void init_queue(_QUEUE *q)
{
q->rear= q->front= 0;
q->full=0; q->empty=1;
}

int IsFull(_QUEUE *q) {


return(q->full);
}
int IsEmpty(_QUEUE *q) {
return(q->empty);
}

Spring 2012 Programming and Data Structure 74


Queue Example: Contd.
void AddQ(_QUEUE *q, _ELEMENT ob)
{
if(IsFull(q)) {printf("Queue is Full \n"); return;}

q->rear=(q->rear+1)%(MAX_SIZE);
q->q_elem[q->rear]=ob;

if(q->front==q->rear) q->full=1; else q->full=0;


q->empty=0;

return;
}

Spring 2012 Programming and Data Structure 75


Queue Example: Contd.
_ELEMENT DeleteQ(_QUEUE *q)
{
_ELEMENT temp;
temp.name[0]='\0';

if(IsEmpty(q)) {printf("Queue is
EMPTY\n");return(temp);}

q->front=(q->front+1)%(MAX_SIZE);
temp=q->q_elem[q->front];

if(q->rear==q->front) q->empty=1; else q->empty=0;


q->full=0;

return(temp);
}
Spring 2012 Programming and Data Structure 76
Queue Example: Contd.
main() #include <stdio.h>
{ #include <stdlib.h>
int i,j; #include <string.h>
char command[5];
_ELEMENT ob;
_QUEUE A;

init_queue(&A);

command[0]='\0';
printf("For adding a name use 'add [name]'\n");
printf("For deleting use 'delete' \n");
printf("To end the session use 'bye' \n");

Spring 2012 Programming and Data Structure 77


Queue Example: Contd.
while (strcmp(command,"bye")!=0){
scanf("%s",command);

if(strcmp(command,"add")==0) {
scanf("%s",ob.name);
if (IsFull(&A))
printf("No more insertion please \n");
else {
AddQ(&A,ob);
printf("Name inserted %s \n",ob.name);
}
}

Spring 2012 Programming and Data Structure 78


Queue Example: Contd.
if (strcmp(command,"delete")==0) {
if (IsEmpty(&A))
printf("Queue is empty \n");
else {
ob=DeleteQ(&A);
printf("Name deleted %s \n",ob.name);
}
}
} /* End of while */
printf("End session \n");
}

Spring 2012 Programming and Data Structure 79


Terminology
• Infix
-3+4
• Postfix
-3 4 +
• Prefix
+ -3 4

6-80
Postfix Expressions
• The calculation: ((1 + 2) * 4) + 3 can
be written down in postfix notation
with the advantage of no
precedence rules and no
parentheses needed.

1 2 + 4 * 3 +

6-81
• The expression is evaluated from
the left to right using a stack:
– when encountering an operand, push
the operand
– when encountering an operator, pop
two operands and evaluate the value
then push the result.

6-82
Solution
– when encountering an 1 2 + 4 * 3 +
operand, push the operand
– when encountering an
operation, pop two
operands and evaluate the
value then push the result.

6-83
Stack Usage
Examples
– Browser “back” button: takes you to the page visited before the current page
– Editor “undo” button: takes you to the state of the document before the current
state
– Process stacks: stores call frames to support method calls. The call frame on top of
the stack is the currently executing method, the call frame below it represents the
method invoked before the current method, and so on
– Many virtual machines are also stack-oriented, including the
p-code machine and the Java virtual machine.

6-84
Properties
• Stack: a Last-In-First-Out (LIFO) data structure –
the last item into the stack is the first out of it
– Attributes: top – references the element on top of the
stack
– Operations: push(element), pop(), peek(), isEmpty(),
size()

6-85
Stack Operations
Stack()
pre-condition: none
responsibilities: constructor – initialize the stack attributes
post-condition: size is 0
top refers to null (a special value not part of
the stack)
returns: nothing
push( Type )
pre-condition: none
responsibilities: push element onto the top of the stack
post-condition: element is placed on top of the stack
size is incremented by 1
top refers to the element pushed
returns: nothing
6-86
Stack Operations

pop()
pre-condition: isEmpty() is false
responsibilities: remove and return the element at top
post-condition: the top element is no longer in the stack
size is decremented by 1
top refers to the element below the previous
topmost element or null if the stack is empty
returns: the element removed
throws: empty stack exception if pre-condition is not
met

6-87
Stack Operations
peek()
pre-condition: isEmpty() is false
responsibilities: return the element at top
post-condition: the stack is unchanged
returns: the element referenced by top
throws: empty stack exception if pre-condition is not
met

6-88
Goals for the Stack
• Hide implementation details from the client
– Put only the interface in stack.h, and implementation in stack.c
– Only allow the client to have a pointer to a Stack
• Allow multiple instances of stacks in the same program
– Define a type of Stack, rather than a global variable in stack.c
• Allow different stacks to have different kinds of elements
– Allow another abstract data type to define the type of Item
– Only allow the Stack to refer to a pointer to an Item
• Allow different stacks with different element types in the
same program
– Using void pointers
Stack Interface (stack.h)

#ifndef STACK_INCLUDED What’s this for?


#define STACK_INCLUDED

typedef struct Item *Item_T;


typedef struct Stack *Stack_T;

Stack_T Stack_new(void);
int Stack_empty(Stack_T stk);
void Stack_push(Stack_T stk, Item_T item);
Item_T Stack_pop(Stack_T stk);

#endif
Notes on stack.h
• Type Stack_T is an opaque pointer
– Clients can pass Stack_T around but can’t look inside
– Definition of Stack can change without recompiling the client
code
• Type Item_T is also an opaque pointer
– … but defined in some other ADT
– So, Stack implementation doesn’t need to know about it
– And, Stack implementation can be used for many kinds of items
• Stack_ is a disambiguating prefix
– A convention that helps avoid name collisions
Stack Implementation: Array
stack.c
#include <assert.h>
#include <stdlib.h>
#include “stack.h”

enum {CAPACITY = 1000};

struct Stack {
int count;
Item_T data[CAPACITY];
};

Stack_T Stack_new(void) {
Stack_T stk = malloc(sizeof(*stk));
assert(stk != NULL);
stk->count = 0;
return stk;
}
Careful Checking With Assert
stack.c
#include <assert.h>
#include <stdlib.h>
#include “stack.h”

enum {CAPACITY = 1000};

struct Stack {
int count;
Item_T data[CAPACITY];
};

Stack_T Stack_new(void) {
Stack_T stk = malloc(sizeof(*stk));
assert(stk != NULL);
stk->count = 0;
return stk; Make sure stk!
} =NULL, or halt the
program!
Stack Implementation: Array (Cont.)
int Stack_empty(Stack_T stk) {
assert(stk != NULL);
return (stk->count == 0);
}
void Stack_push(Stack_T stk, Item_T item) {
assert(stk != NULL);
assert(stk->count < CAPACITY); 0
stack->data[stack->count] = item; 1
stack->count++; 2
} 3
Item_T Stack_pop(Stack_T stk) { 4
assert(stk != NULL); 5
assert(stk->count > 0); count is 3
stk->count--;
CAPACITY is 6
return stk->data[stk->count];
}
Problems With Array Implementation

CAPACITY too large: waste memory

data wasted space

CAPACITY too small:

data

assertion failure (if you were careful)


buffer overrun (if you were careless)
Linked List Would be Better…

struct List {
val int val;
next struct List *next;
} *head;

head empty stack

push(1); push(2); push(3);

3 2 1
head
Popping and Pushing
3 2 1
head

pop( );

3 2 1
head

4 push(4);

2 1
head
Stack Implementation: Linked List
stack.c
#include <assert.h>
#include <stdlib.h>
#include “stack.h”

struct Stack {struct List *head;};


struct List {Item_T val; struct List *next;};

Stack_T Stack_new(void) {
Stack_T stk = malloc(sizeof(*stk));
assert(stk != NULL);
stk->head = NULL;
return stk;
}
Stack Implementation: Linked List
int Stack_empty(Stack_T stk) {
assert(stk != NULL);
return (stk->head == NULL);
}

void Stack_push(Stack_T stk, Item_T item) {


struct List *t = malloc(sizeof(*t));
assert(t != NULL); t
assert(stk != NULL); 4
t->val = item;
t->next = stk->head;
3 2 1
stk->head = t;
} head
stack.c, continued
Item_T Stack_pop(Stack_T stk) {
Item_T x;
struct List *p;
assert(stk != NULL);
assert(stk->head != NULL);
x = stk->head->val;
p = stk->head;
stk->head = stk->head->next;
free(p);
return x;
} 3 2 1
head
Client Program: Uses Interface
client.c
#include <stdio.h>
#include <stdlib.h>
#include “item.h”
#include “stack.h”

int main(int argc, char *argv[]) {


int i;
Stack_T s = Stack_new();
for (i = 1; i < argc; i++)
Stack_push(s, Item_new(argv[i]));
while (!Stack_empty(s))
Item_print(Stack_pop(s));
return 0;
Problem: Multiple Kinds of Stacks?
• Good, but still not flexible enough
– What about a program with multiple kinds of stacks
– E.g., a stack of books, and a stack of pancakes
– But, you can only define Item_T once
• Solution in C, though it is a bit clumsy
–typedef
Don’t struct Item *Item_T;
define Item_T (i.e., let it be a “void *”)
typedef struct Stack *Stack_T;
– Good flexibility, but you lose the C type checking
Stack_T Stack_new(void);
int Stack_empty(Stack_T stk);
void Stack_push(Stack_T stk, void *item);
void *Stack_pop(Stack_T stk);
stack.h (with void*)

#ifndef STACK_INCLUDED
#define STACK_INCLUDED

typedef struct Item *Item_T;


typedef struct Stack *Stack_T;

Stack_T Stack_new(void);
int Stack_empty(Stack_T stk);
void Stack_push(Stack_T stk, void *item);
void *Stack_pop(Stack_T stk);

#endif
Stack Implementation (with void*)
stack.c
#include <assert.h>
#include <stdlib.h>
#include “stack.h”

struct Stack {struct List *head;};


struct List {void *val; struct List *next;};

Stack_T Stack_new(void) {
Stack_T stk = malloc(sizeof(*stk));
assert(stk);
stk->head = NULL;
return stk;
}
stack.c (with void*) continued
int Stack_empty(Stack_T stk) {
assert(stk != NULL);
return stk->head == NULL;
}

void Stack_push(Stack_T stk, void *item) {


Stack_T t = malloc(sizeof(*t));
assert(t != NULL);
assert(stk != NULL);
t->val = item;
t->next = stk->head;
stk->head = t;
}
stack.c (with void*) continued
void *Stack_pop(Stack_T stk) {
void *x;
struct List *p;
assert(stk != NULL);
assert(stk->head != NULL);
x = stk->head->val;
p = stk->head;
stk->head = stk->head->next;
free(p);
return x;
}
Client Program (With Void)
client.c (with void*)
#include <stdio.h>
#include <stdlib.h>
#include “item.h”
#include “stack.h”

int main(int argc, char *argv[]) {


int i;
Stack_T s = Stack_new();
for (i = 1; i < argc; i++)
Stack_push(s, Item_new(argv[i]));
while (!Stack_empty(s))
printf(“%s\n”,Stack_pop(s));
return 0;
}
Structural Equality Testing
Suppose we want to test two stacks for equality:

int Stack_equal(Stack_T s1, Stack_T s2);


How can this be implemented?
int Stack_equal(Stack_T s1, Stack_T s2) {
return (s1 == s2);
}
We want to test whether two stacks are equivalent stacks, not
whether they are the same stack.
Almost, But Not Quite...
How about this:
int Stack_equal(Stack_T s1, Stack_T s2) {
struct List *p, *q;
for (p=s1->head, q=s2->head; p && q;
p=p->next, q=q->next)
if (p->val != q->val)
return 0;
return p==NULL && q==NULL;
}
This is better, but what we want to test whether s1->val is
equivalent to s2->val, not whether it is the same.
Item ADT Provides Equal Test
How about this:
int Stack_equal(Stack_T s1, Stack_T s2) {
struct List *p, *q;
for (p=s1->head, q=s2->head; p && q;
p=p->next, q=q->next)
if ( ! Item_equal(p->val, q->val))
return 0;
return p==NULL && q==NULL;
}
This is good for the “Item_T” version of stacks (provided the
Item interface has an Item_equal function), but what about
the void* version of stacks?

You might also like