Abstract Data Types Abstract Data Types A useful
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 String. Copy (src. String, dst. String) Boolean String. Concat (src. String, dst. String) Boolean String. Compare (Src. String, dst. String) Void String. Print (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 { int numerator; int denominator; }RATIONAL; int numerator (RATIONAL r) { return r. numerator; } int denominator (RATIONAL r) { return r. denominator; } RATIONAL makerational (int x, int y) { RATIONAL r; r. numerator = x; r. denominator = y; return r; } RATIONAL reduce (RATIONAL r) { int g; g = gcd(r. numerator, r. denominator); r. numerator /= g; r. denominator /= g; return r; }
ADT: Rational Number implementation of add (1) typedef struct { int numerator; int denominator; } RATIONAL; RATIONAL add (RATIONAL r 1, RATIONAL r 2) { RATIONAL r; int g; g = gcd(r 1. denominator, r 2. denominator); r. denominator = lcm(r 1. denominator, r 2. denominator); r. numerator = r 1. denominator*r 2. denominator/g; r. numerator += r 2. denominator*r 1. numerator/g; return r; }
ADT: Rational Number implementation of add (2) typedef struct { int numerator; int denominator; }RATIONAL; RATIONAL add (RATIONAL r 1, RATIONAL r 2) { RATIONAL r; r. numerator = r 1. numerator*r 2. denominator +r 2. numerator*r 1. denominator; r. denominator=r 1. denominator*r 2. denominator; return r; }
ADT: Rational Number Concrete implementation I typedef struct { int numerator; int denominator; }RATIONAL; RATIONAL mult (RATIONAL r 1, RATIONAL r 2) { RATIONAL r; r. numerator = r 1. numerator*r 2. numerator; r. denominator = r 1. denominator*r 2. denominator; r = reduce (r); return r; } int equal (RATIONAL r 1, RATIONAL r 2) { return (r 1. numerator*r 2. denominator==r 2. numerator*r 1. denominator); } void printrat (RATIONAL r) { printf (“%d / %d “, r. numerator, r. denominator); }
ADT: Rational Number Concrete implementation II typedef struct { int ar[2] ; }RATIONAL; RATIONAL makerational (int x, int y) { RATIONAL r; r. ar[0] = x; r. ar[1] = y; return r; } int numerator (RATIONAL r) { return r. a[0]; } int denominator (RATIONAL r) { return r. a[1]; } RATIONAL reduce (RATIONAL r) { int g; g = gcd (r. numerator, r. denominator); r. a[0] /= g; r. a[1] /= g; return r; }
The List ADT • A list : <A 1, A 2, . . . , 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 find. Kth (LIST)
Array Implementation of List typedef int ETYPE; typedef struct { ETYPE elements[MAXS]; int size; } LIST; LIST makenull () ; LIST make. List (ETYPE) ; void print. List (LIST) ; int Is. Empty (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): SET makenullset () ; int member (ETYPE, SET) ; SET adjoin (ETYPE, SET); SET union (SET, SET) ; SET intersection (SET, SET); void printset (SET) ; Interface functions (2): SET makenullset () ; int member (ETYPE, SET) ; void adjoin(ETYPE, SET *); void union (SET, SET*); void intersection (SET, 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 Spring 2012 Programming and Data Structure 29
STACK USING ARRAY POP 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 is. Empty(stack *) ; int is. Full(stack *) ;
stack. c #include "stack. h" void init(stack *s) { s->tos = -1; } int push(stack *s, int n) { if(is. Full(s)) { printf("The STACK is fulln"); return ERROR ; } s->tos++; s->data[s->tos]=n; return OK ; } int Pop(stack *s) { if(is. Empty(s)) { printf("The STACK is emptyn"); return ERROR ; } s -> tos-- ; return OK ; } int is. Full(stack *s) { return s->tos == SIZE-1; } int is. Empty(stack *s) { return s->tos == -1; }
stack. c int Top(stack *s , int *val) { if (is. Empty(s)) { printf("The STACK is emptyn") ; return ERROR ; } *val = (s -> data[s -> tos]) ; return OK ; }
Array Implementation of Stack CAPACITY too large: waste memory data CAPACITY too small: data wasted space
Compiling the datatype $ gcc -c stack. c We get the object module stack. o. We can construct library from it.
User Program: test. Stack. c #include <stdio. h> #include "stack. h" int main() // test. Stack. c { stack s ; int x , err , val ; char c ; init(&s); printf(" ’U’ for push (U 15)n ’O’ for popn ’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("%dn", val); break; case ’n’ : case ’t’ : case ’ ’ : break; default : printf("Token Unknownn"); } return 0; }
Compiling the user program • $ gcc -Wall test. Stack. 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 stacknode { int data ; struct stacknode *next ; }; typedef struct stacknode *stack ;
Interface functions (stackl. h) #include <stdio. h> #include <stdlib. h> #define ERROR 1 #define OK 0 struct stacknode { int data ; struct stacknode *next ; }; typedef struct stacknode, *stack ; #define INIT(s) ((s)=NULL) #define ISEMPTY(s) ((s) == NULL) int push(stack * , int) ; int pop(stack *) ; int top(stack, int *) ;
Implementation File: stack. SR. c #include "stack. SR. h" int push(stack *s, int n) { // stack. SR. c stack temp ; temp=(stack)malloc(sizeof(node)) ; if(temp == NULL) { printf("The STACK is fulln"); return ERROR ; } temp->data=n; temp->next=*s ; *s = temp ; return OK ; }
stack. SR. c continued int pop(stack *s) { stack temp ; if(ISEMPTY(*s)) { printf("The STACK is emptyn"); return ERROR ; } temp=*s; *s=(*s)->next ; free(temp) ; return OK ; }
stack. SR. c continued int top(stack s , int *val) { if(ISEMPTY(s)) { printf("The STACK is emptyn") ; return ERROR ; } *val = s -> data ; return OK ; }
User Program: test. Stack. c #include <stdio. h> #include "stack. SR. h" int main() // test. Stack. SR. c { stack s ; int x , err , val ; char c ; INIT(s); printf(" ’U’ for push (U 15)n ’O’ for popn ’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("%dn", val); break; case ’n’ : case ’t’ : case ’ ’ : break; default : printf("Token Unknownn"); } 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 • Neat trick: use a circular array to insert and 6 remove items from a queue in constant 5 time • The idea of a circular array is that the end of the array “wraps around” to the start of the array 7 0 1 2 4 3
Figure 5 -16 Queue will overgrow the array • Should we use VERY L A R G E ARRAYS?
Array implementation of queues queue. Ary maxsize count 7 4 front 11 37 front rear 1 5 rear 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. #define MAX 200 typedef struct { int data[MAX] ; int front , rear, count; } queue 2; The queue may contain MAX data.
Queue on Circular Array: Operations void init(queue *) ; int add(queue *, int) ; int delete(queue *); int front(queue *, int *) ; int is. Empty(queue *) ; int is. Full(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 is. Empty(queue *); int is. Full(queue *);
Implementation File: queue. c #include "queue. h" void init(queue *q) { q->front=q->rear=0; } int is. Empty(queue *q) { return q->rear == q->front; } int is. Full(queue *q) { return (q->rear+1)%MAX == q->front; }
int add(queue *q, int n) { if (is. Full(q)) return ERROR; q->data[q->rear]=n; q->rear=(q->rear+1)%MAX; return OK ; } int delete(queue *q) { if (is. Empty(q)) return ERROR ; q->front=(q->front+1)%MAX ; return OK ; }
int front(queue *q , int *v) { if (is. Empty(q)) return ERROR ; *v=q->data[(q->front)%MAX] ; return OK ; }
User Program: test. Queue. 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 deleten ’F’ for frontn ’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 fulln") ; break; case ’D’ : err = delete(&q); if(err) printf("Q emptyn") ; break; case ’F’ : err = front(&q , &val)
if(err) printf("Q emptyn") ; else printf("%dn", val); break; case ’n’ : case ’t’ : case ’ ’ : break; default : printf("Token Unknownn"); } return 0 ; }
END
- Slides: 62