<<

Overview

Lecture P5: Abstract Data Types :

of values and collection of operations on those values.

■ Ex. short int – set of values between -32,768 and 32,767 – arithmetic operations: + - * / %

Abstract data type (ADT):

■ Data type whose representation is HIDDEN.

■ Don’t want client to directly manipulate data type.

■ Operations ONLY permitted through .

Separate implementation from specification.

■ INTERFACE: specify the allowed operations

■ IMPLEMENTATION: provide code for operations

■ CLIENT: code that uses operations

1/27/00 Copyright © 2000, Kevin Wayne P5.1 1/27/00 Copyright © 2000, Kevin Wayne P5.2

Advantages of ADT’s Complex Number Data Type

Different clients can share the same ADT. Create to represent complex numbers.

■ See Sedgewick 4.8. Can change ADT without changing clients. ■ Store in rectangular form: real and imaginary parts.

Client doesn’t (need to) know how implementation works.

typedef struct { Convenient way to organize large problems. double re; ■ Decompose into smaller problems. double im; ■ Substitute alternate solutions. } Complex;

■ Separation compilation.

■ Build libraries.

Powerful mechanism for building layers of abstraction.

■ Client works at a higher level of abstraction.

1/27/00 Copyright © 2000, Kevin Wayne P5.3 1/27/00 Copyright © 2000, Kevin Wayne P5.4 Complex Number Data Type: Interface Complex Number Data Type: Client

Interface lists allowable operations on complex data type. Client program uses interface operations to calculate something:

COMPLEX.h client.c

typedef struct { #include double re; #include “COMPLEX.h” client can use interface double im; interface goes in .h file } Complex; int main(void) {

Complex COMPLEXadd (Complex, Complex); . . . your favorite application Complex COMPLEXmult (Complex, Complex); . . . that uses complex numbers Complex COMPLEXpow (Complex, int); Complex COMPLEXconj (Complex); return 0; double COMPLEXmod (Complex); } double COMPLEXreal (Complex); double COMPLEXimag (Complex); Complex COMPLEXinit (double, double); void COMPLEXprint(Complex);

1/27/00 Copyright © 2000, Kevin Wayne P5.5 1/27/00 Copyright © 2000, Kevin Wayne P5.6

Complex Number Data Type: Implementation Complex Number Data Type: Implementation

Write code for interface functions. Write code for interface functions.

complex.c complex.c (cont)

#include “COMPLEX.h” implementation needs to double COMPLEXmod(Complex a) { know interface return sqrt(a.re * a.re + a.im * a.im); } Complex COMPLEXadd (Complex a, Complex b) { Complex t; void COMPLEXprint(Complex) { t.re = a.re + b.re; printf(“%f + %f i\n”, a.re, a.im); t.im = a.im + b.im; } return t; } Complex COMPLEXinit(double x, double y) { Complex t; Complex COMPLEXmult(Complex a, Complex b) { t.re = x; Complex t; t.im = y; t.re = a.re * b.re - a.im * b.im; return t; t.im = a.re * b.im + a.im * b.re; } return t; }

1/27/00 Copyright © 2000, Kevin Wayne P5.7 1/27/00 Copyright © 2000, Kevin Wayne P5.8 Separate Compilation Can Change Implementation

Client and implementation both include COMPLEX.h Can use alternate representation of complex numbers.

■ Store in polar form: modulus and angle. Can be compiled jointly. %gcc client.c complex.c z = x + i y = r ( cos θ + i sin θ ) = r ei θ Can be compiled separately. %gcc -c complex.c %gcc -c client.c %gcc client.o complex.o typedef struct { double r; double theta; } Complex;

1/27/00 Copyright © 2000, Kevin Wayne P5.9 1/27/00 Copyright © 2000, Kevin Wayne P5.10

Alternate Interface Alternate Implementation

Interface lists allowable operations on complex data type. Write code for interface functions.

COMPLEX.h complex.c

typedef struct { #include “COMPLEX.h” double r; double theta; Complex COMPLEXmod(Complex a) { } Complex; return a.r; } Complex COMPLEXadd (Complex, Complex); Complex COMPLEXmult (Complex, Complex); Complex COMPLEXmult(Complex a, Complex b) { Complex COMPLEXpow (Complex, int); Complex t; Complex COMPLEXconj (Complex); t.modulus = a.r * b.r; double COMPLEXmod (Complex); t.angle = a.theta + b.theta; double COMPLEXreal (Complex); } double COMPLEXimag (Complex); Complex COMPLEXinit (double, double); Some interface functions are void COMPLEXprint(Complex); now much easier to code up.

1/27/00 Copyright © 2000, Kevin Wayne P5.11 1/27/00 Copyright © 2000, Kevin Wayne P5.12 Alternate Implementation Multiple Implementations

Write code for interface functions. Usually, there are several ways to represent and implement a data type.

complex.c Which is better: rectangular or polar representation of Complex numbers?

■ Depends on application. #include ■ Rectangular are better for additions and subtractions. Complex COMPLEXadd(Complex a, Complex b) { – no need to evaluate arctangent function Complex t; ■ Polar are better for multiply and modulus. double x, y; x = a.r * cos(a.theta) + b.r * cos(b.theta); – no need to take square roots y = a.r * sin(a.theta) + b.r * sin(b.theta); ■ Get used to making tradeoffs. t.r = sqrt(x*x + y*y); t.theta = arctan(y/x); This example may seem artificial. return t; } ■ Essential for many real applications. . .

Others are more annoying.

1/27/00 Copyright © 2000, Kevin Wayne P5.13 1/27/00 Copyright © 2000, Kevin Wayne P5.14

Rational Number Data Type “Non ADT’s”

See Assignment 3. Is Complex data type an ?

■ You will create data type for Rational numbers. ■ NO: Representation in interface.

■ Add associated operations (add, multiply, reduce) to Rational number – Client can directly manipulate the data type: a.re = 5.0;

data type. ■ Difficult to hide representation with user-defined sets of values.

■ Possible to fix (see Sedgewick 4.8 or COS 217).

typedef struct { int p; /* numerator */ Are C built-in types like int ADT’s?

int q; /* denominator */ ■ ALMOST: we generally ignore representation. } Rational; ■ NO: set of values depends on representation. – might use (x & 1) to test if odd – works only if they’re stored as two’s complement integers

■ CONSEQUENCE: strive to write programs that function properly independent of representation. – (x % 2) is portable way to test if odd – also, use for machine-specific ranges of int, long

1/27/00 Copyright © 2000, Kevin Wayne P5.15 1/27/00 Copyright © 2000, Kevin Wayne P5.16 ADT’s for Stacks and Queues Stack Interface and Client

Prototypical data type. void STACKinit(void); ■ Set of operations (insert, delete) on generic data. int STACKempty(void); STACK of integers void STACKpush(int); Stack (“last in first out” or LIFO) int STACKpop(void);

■ push: add info to the data structure

■ pop: remove the info MOST recently added STACK.h #include “STACK.h” ■ initialize, test if empty int main(void) { int a, b; Queue (“first in first out” or FIFO) . . .

■ put: add info to the data structure STACKinit(); client uses data type, without STACKpush(a); ■ get: remove the info LEAST recently added regard to how it is represented . . . ■ initialize, test if empty or implemented. b = STACKpop(); return 0; Could use EITHER array or linked list see Lecture P7 } to implement EITHER stack or queue. client.c

1/27/00 Copyright © 2000, Kevin Wayne P5.17 1/27/00 Copyright © 2000, Kevin Wayne P5.18

Stack Implementation with Arrays Compilation

Push and pop at the end of array. Client and implementation both include STACK.h #include #include “STACK.h” Demo: Can be compiled jointly. int s[1000]; int N; %gcc client.c stackarray.c Drawback: void STACKinit(void) { ! Have to reserve space for N = 0; Can be compiled separately. max size. } %gcc -c stackarray.c int STACKempty(void) { %gcc -c client.c return N == 0; %gcc client.o stackarray.o }

void STACKpush(int item) { s[N++] = item; }

int STACKpop(void) { return s[--N]; } stackarray.c

1/27/00 Copyright © 2000, Kevin Wayne P5.19 1/27/00 Copyright © 2000, Kevin Wayne P5.20 Balanced Parentheses Balanced Parentheses

parentheses.c parentheses.c (cont)

int balanced(char a[]) { #include int i; #include "STACK.h" STACKinit(); #define NMAX 1000 for (i = 0; a[i] != '\0'; i++) { push all left if (a[i] == '(') int main(void) { Read from stdin, ignoring parentheses STACKpush(a[i]); int c, i = 0; non-parentheses else if (a[i] == ')') { char a[NMAX]; if (STACKempty()) return 0; check for matching if (STACKpop() != '(') return 0; while ((c = getchar()) != EOF)) left parenthesis } if (c == '(' || c == ')’) } a[i++] = c; balanced if stack is empty return STACKempty(); a[i] = '\0'; when no more input } if (balanced(a)) printf("balanced\n"); check if balanced else printf("unbalanced\n"); return 0; ( ( ( ) ( ) ) ) Good: } Bad: ( ( ) ) ) ( ( )

1/27/00 Copyright © 2000, Kevin Wayne P5.21 1/27/00 Copyright © 2000, Kevin Wayne P5.22

Balanced Parentheses ADT Review

Check if your C program has unbalanced parentheses. Client can access data type ONLY through implementation.

■ Example: STACK implementation. Unix % gcc parentheses.c stackarray.c Representation is HIDDEN in the implementation.

% a.out < myprog.c ■ Implementation uses arrays. % balanced ■ Client is completely unaware of this. % % a.out < parentheses.c % unbalanced Can change ADT without changing clients at all.

■ In Lecture P7 we implement stack using linked lists instead of arrays. How could valid C program have ■ Obtain different time / space tradeoffs. unbalanced parentheses?

Exercise: extend to handle square and curly braces.

■ Good: { ( [ ( [ ] ) ( ) ] ) }

■ Bad: ( ( [ ) ] )

1/27/00 Copyright © 2000, Kevin Wayne P5.23 1/27/00 Copyright © 2000, Kevin Wayne P5.24 First Class ADT Reverse Polish (Postfix) Notation

So far, only 1 stack or queue per program. STACKinit(); Practical example of use of stack abstraction. . . . STACKpush(a); Put operator after operands in expression. . . . ■ Use stack to evaluate. b = STACKpop(); – operand: push it onto stack. – operator: pop operands, push result.

First Class ADT: ■ Systematic way to save intermediate results.

■ ADT that is just like a built-in C type. Stack s1, s2;

■ Can declare multiple instances of them. Example 1. s1 = STACKinit(); ■ Pass specific instances of them to ■ 1 2 3 4 5 * + 6 * * 7 8 9 + + * + interface as inputs. s2 = STACKinit(); . . . ■ Details omitted in COS 126 - see STACKpush(s1, a); Sedgewick 4.8 or COS 226 if interested. STACKpush(s2, b); . . . c = STACKpop(s2);

1/27/00 Copyright © 2000, Kevin Wayne P5.25 1/27/00 Copyright © 2000, Kevin Wayne P5.26

Reverse Polish (Postfix) Notation

Practical example of use of stack abstraction.

Put operator after operands in expression.

■ Use stack to evaluate. – operand: push it onto stack. – operator: pop operands, push result.

■ Systematic way to save intermediate results.

Example 2a: convert 97531 from hex to decimal.

■ 9 16 16 16 16 * * * * 7 16 16 16 * * * 5 16 16 * * 3 16 * 1 + + + +

Example 2b: convert 97531 from hex to decimal.

■ 9 16 * 7 + 16 * 5 + 16 * 3 + 16 * 1 +

■ Stack never has more than two numbers on it!

■ Horner’s method (see lecture A3).

1/27/00 Copyright © 2000, Kevin Wayne P5.28