• No results found

Abstract Data Types (ADTs)

N/A
N/A
Protected

Academic year: 2021

Share "Abstract Data Types (ADTs)"

Copied!
33
0
0

Loading.... (view fulltext now)

Full text

(1)

Abstract Data Types (ADTs)

Professor Jennifer Rexford COS 217

(2)

Preparing for the Midterm Exam

• Exam logistics

 Date/time: Wednesday March 12 in lecture

 Open books, open notes, open mind, but not open laptop/PDA

 Covering material from lecture, precept, and reading, but not tools

• Preparing for the midterm

 Lecture and precept materials available online

 Course textbooks, plus optional books on reserve

 Office hours and the course listserv

• Old exams from previous semesters

 Midterms: http://www.cs.princeton.edu/courses/archive/spring08/cos217/exam1old/

 Finals: http://www.cs.princeton.edu/courses/archive/spring08/cos217/exam2old/

(3)

Abstract Data Type (ADT)

• An ADT module provides:

 Data type

 Functions that operate on the type

• Client does not manipulate the data representation directly

 The client should just call functions

• “Abstract” because the observable results (obtained by client) are independent of the data representation

 Separation of interface and implementation

• Programming language support for ADT

 Ensure that client cannot possibly access representation directly

 C++, Java, other object-oriented languages have private fields

(4)

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

• Interface functions

 MakeRational

 AddRational

 MultiplyRational

 EqualRational

 PrintRational

 ReduceRational

(5)

Several Ways to Represent Rational

typedef struct { int numerator;

int denominator;

} Rational;

typedef struct {

int ar[2];

(6)

Another Example ADT: Sets

• Sets

 A collection of elements

• Interface functions

 MakeNullSet

 IsMember

 Insert

 Delete

 Union

 Intersection

(7)

Several Ways to Represent Sets

typedef struct {

Etype elem[MAX];

int size;

} Set;

Or, as a linked list…

(8)

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

(9)

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

(10)

Stack Interface (stack.h)

#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, Item_T item);

Item_T Stack_pop(Stack_T stk);

#endif

What’s this for?

(11)

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

(12)

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;

(13)

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;

Make sure stk!=NULL,

(14)

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);

stack->data[stack->count] = item;

stack->count++;

}

Item_T Stack_pop(Stack_T stk) { assert(stk != NULL);

assert(stk->count > 0);

stk->count--;

return stk->data[stk->count];

01 23 45

count is 3

(15)

Problems With Array Implementation

CAPACITY too large: waste memory

CAPACITY too small:

assertion failure (if you were careful) buffer overrun (if you were careless)

wasted space data

data

(16)

Linked List Would be Better…

next val

head

3 2 1

empty stack

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

struct List { int val;

struct List *next;

} *head;

(17)

Popping and Pushing

pop( );

head

3 2 1

head

3 2 1

2 1

4 push(4);

(18)

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;

(19)

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);

assert(stk != NULL);

t->val = item;

t->next = stk->head;

stk->head = t;

}

4 t

(20)

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

(21)

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));

(22)

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

 Don’t define Item_T (i.e., let it be a “void *”)

 Good flexibility, but you lose the C type checking typedef struct Item *Item_T;

typedef struct Stack *Stack_T;

Stack_T Stack_new(void);

int Stack_empty(Stack_T stk);

(23)

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

(24)

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;

(25)

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;

(26)

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;

(27)

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));

(28)

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.

(29)

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;

}

Almost, But Not Quite...

(30)

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 ADT Provides Equal Test

(31)

How about this:

int Stack_equal(Stack_T s1, Stack_T s2,

int (*equal)(void *, void *)) { struct List *p, *q;

for (p=s1->head, q=s2->head; p && q;

p=p->next, q=q->next)

if ( ! equal((void*)p->val, (void*) q->val)) return 0;

return p==NULL && q==NULL;

}

Function Pointers

(32)

int Stack_equal(Stack_T s1, Stack_T s2,

int (*equal)(void *, void *)) { struct List *p, *q;

for (p=s1->head, q=s2->head; p && q;

p=p->next, q=q->next)

if ( ! equal((void*)p->val, (void*) q->val)) return 0;

return p==NULL && q==NULL;

}

Client:

int char_equal (char *a, char *b) { return (!strcmp(a,b));

}

int string_stacks_equal(Stack_T st1, Stack_T st2) { return Stack_equal(st1, st2,

Passing a Function Pointer

(33)

Conclusions

• Abstract Data Types (ADTs)

 Separation of interface and implementation

 Don’t even allow the client to manipulate the data directly

• Example of a stack

 Implementation #1: array

 Implementation #2: linked list

• Void pointers

 To allow multiple kinds of elements in the same program

 At the expense of type checking

References

Related documents

The result of sorting the data will be to group like elements together (see figure 6) so that any unwanted portions of the report can be eliminated and the core report information

Calculate the density of the concrete used to prepare the BALL, considering the mass and the volume of the BALL (the volume is the one calculated in Step 1).. The value

Bike handling of typedef declaring a typedef declaration is structure in the function returns a function pointer declaration does fork offset from the below?. Access one is like lack

◦  Supports the roll out a new Medicaid billable service (Community Support Services). ◦  Contracting and funding policies and

2.02.01 As with the Living Wage calculations the Family Living Income calculations are derived from the Irish Minimum Essential Budget Standards model (see Section 1.05, page 4),

Defines a structure that contains the function pointers used to configure behavior of NSHashTable with respect to elements within a hash table.. typedef

Least in that directly declare in the analytics and declare an anonymous structure as the website usable by the struct in headers being processed may just as i do. Good for

Etymology. The specific epithet, rio , is a noun in apposition and refers to the type locality. Type locality: de Villa Victoria, Ch. Specimens of this species superficially