Upload
tanisha-gilliam
View
89
Download
0
Embed Size (px)
DESCRIPTION
Data Structure & Abstract Data Type. C and Data Structures Baojian Hua [email protected]. Data Types. A data type consists of: A collection of data elements (a type) A set of operations on these data elements Data types in languages: predefined: - PowerPoint PPT Presentation
Citation preview
Data Types A data type consists of:
A collection of data elements (a type) A set of operations on these data elements
Data types in languages: predefined:
any language defines a group of predefined data types (In C) int, char, float, double, …
user-defined: allow programmers to define their own (new) data typ
es (In C) struct, union, …
Data Type Examples Predefined:
type: int elements: …, -2, -1, 0, 1, 2, … operations: +, -, *, /, %, …
User-defined: type: complex elements: 1+3i, -5+8i, … operations: newComplex, add, distance,
…
Abstract Data Types An abstract data type:
separates data type definition from representation
separates function declaration (prototypes) from implementation
Example of abstract data types in languages interfaces in Java signatures in ML (roughly) header files & typedef in C
Data Structures Data structure studies the organization of d
ata in computers, consisting of the (abstract) data types (definition and repr’) relationship between elements of this type operations on data types
Algorithms: methods to operate on data structures
tradeoff between efficiency and simplicity subtle interplay with data structure design
Slogan: program = data structures+algorithm
What will this course cover? Linear structure:
Linked list, stack, queue, extensible array, functional string
Tree & forest: binary tree, binary search tree
Graph Hash Searching
More on Modules and Abstract Data Types
Consider a data type to represent natural number n: a data type called “nat” elements: 0, 1, 2, 3, … operations: newNat, add, sub, …
How to represent this (abstract) data type in C?
“nat” ADT in C (Interface)// in file “nat.h”#ifndef NAT_H#define NAT_H
typedef struct nat *nat;
nat newNat (int i);nat natAdd (nat n1, nat n2);// other function prototypes are similar
#endif
Client Code// in file “main.c”#include “nat.h”
int main (){ nat n1, n2, n3; n1 = newNat (8); n2 = newNat (9); n3 = natAdd (n1, n2);
return 0;}
“nat” Implementation// in file “nat.c”#include <stdlib.h>#include “nat.h”
struct nat{ int i; // the concrete internal representation};
nat newNat (int i){ nat n = malloc (sizeof (*n)); n->i = i; return n;}
i
n
“nat” Implementation// in file “nat.c”#include <stdlib.h>#include “nat.h”
struct nat{ int i; // the concrete internal representation};nat newNat (int i){ if (i<0) error (“invalid arg\n”); nat n = malloc (sizeof (*n)); n->i = i; return n;}
i
n
“nat” Implementation// in file “nat.c”#include <stdlib.h>#include “nat.h”
struct nat{ int i; // the concrete internal representation};nat natAdd (nat n1, nat n2){ nat n = malloc (sizeof (*n)); n->i = n1->i + n2->i; return n;}
i
n1
i
n2
n1->i +n2->i
n
Client Code// in file “main.c”#include “nat.h”
int main (){ nat n1, n2, n3; n1 = newNat (8); n2 = newNat (9); n3 = natAdd (n1, n2);
// but what if we want to print nat? Is it: // printf (“”, n3) ????
return 0;}
Change to the Interface// in file “nat.h”#ifndef NAT_H#define NAT_H
typedef struct nat *nat;
nat newNat (int i);nat natAdd (nat n1, nat n2);void natPrint (nat n);// other function prototypes are similar
#endif
Change to the Implementation// in file “nat.c”#include <stdlib.h>#include <stdio.h>#include “nat.h”
struct nat{ int i; // the concrete internal representation};
void natPrint (nat n){ printf (“%d”, n->i); return;}
Client Code// in file “main.c”#include “nat.h”
int main (){ nat n1, n2, n3; n1 = newNat (8); n2 = newNat (9); n3 = natAdd (n1, n2);
// but what if we want to print nat? Is it: natPrint (n3);
return 0;}
More on Modules and Abstract Data Types A tuple type has the form: (x, y)
x and y may have different types Tx, Ty Tx, Ty unknown in advance and may be differen
t operations:
newTuple (x, y); // create a new tuple with x and y equals (t1, t2); // equality testing first (t); // get the first element second (t); // get the second element …
How to represent this abstract data type in computers (using C)?
The Tuple ADT Next, we first consider a monomorphic tuple type c
alled “natTuple”: both the first and second components are of “nat” type (2, 3), (8, 9), …
The natTuple ADT: type: natTuple elements: (2, 3), (8, 9), … Operations:
tuple newNatTuple (nat x, nat y); nat first (nat t); Ty second (tuple t); bool equals (tuple t1, tuple t2); …
“natTuple” Interface// in file “natTuple.h”#ifndef NAT_TUPLE_H#define NAT_TUPLE_H
#include “nat.h”
typedef struct natTuple *natTuple;
natTuple newNatTuple (nat n1, nat n2);nat first (natTuple t);nat second (natTuple t);int equals (natTuple t1, natTuple t2);
#endif
Client Code// in file “main.c”#include “nat.h”#include “natTuple.h”
int main (){ nat n1 = newNat (3); nat n2 = newNat (5);
natTuple t1 = newNatTuple (n1, n2);
return 0;}
“natTuple” Implementation// in file “natTuple.c”#include “natTuple.h”
struct natTuple{ nat n1; nat n2;};
natTuple newNatTuple (nat x, nat y){ natTuple t = malloc (sizeof (*t)); t->n1 = x; t->n2 = y; return t;}
n1
n2
t
“natTuple” Implementation// in file “natTuple.c”#include “natTuple.h”
struct natTuple{ nat n1; nat n2;};
nat first (natTuple t){ return t->n1;}
n1
n2
t
“natTuple” Implementation// in file “natTuple.c”#include “natTuple.h”
struct natTuple{ nat n1; nat n2;};
int equals (natTuple t1, natTuple t2){ // the first try (it’s wrong!!): return (t1->n1 == t2->n1 && t1->n2 == t2->n2);}
n1
n2
t1n1
n2
t2
“natTuple” Implementation// in file “natTuple.c”#include “natTuple.h”
struct natTuple{ nat n1; nat n2;};
int equals (natTuple t1, natTuple t2){ // the second try: return (natEquals (t1->n1, t2->n1) && natEquals (t1->n2, t2->n2));}
n1
n2
t1n1
n2
t2
Change to the “nat” Interface// in file “nat.h”#ifndef NAT_H#define NAT_H
typedef struct nat *nat;
nat newNat (int i);nat natAdd (nat n1, nat n2);void natPrint (nat n);int natEquals (nat n1, nat n2);// other function prototypes are similar
#endif
Change to the “nat” Implementation// in file “nat.c”#include <stdlib.h>#include <stdio.h>#include “nat.h”
struct nat{ int i;};
int natEquals (nat n1, nat n2){ return (n1->i == n2->i);}
i
n1
i
n2
“natTuple” Implementation// in file “natTuple.c”#include “natTuple.h”
struct natTuple{ nat n1; nat n2;};
int equals (natTuple t1, natTuple t2){ // the second try: return (natEquals (t1->n1, t2->n1) && natEquals (t1->n2, t2->n2));}
n1
n2
t1n1
n2
t2
The Tuple ADT Finally, we consider a polymorphic tuple
type called “tuple”: “poly”: may take various forms Every components of tuple may be of
different types (2, 3.14), (“8”, ‘a’), (‘\0’, 99), …
The “tuple” ADT: type: tuple elements: (2, 3.14), (“8”, ‘a’), (‘\0’, 99), …
The Tuple ADT
What about operations? tuple newTuple (??? x, ??? y); ??? first (tuple t); ??? second (tuple t); int equals (tuple t1, tuple t2); …
Polymorphic Type To cure this, C offer a polymorphic
type “void *” “void *” is a pointer which can point
to “any” concrete types (i.e., it’s compatible with any pointer type)
think a box or a mask can not be used directly, use ugly cast similar to constructs in others
language, such as “Object”
The Tuple ADT
What about operations? tuple newTuple (void *x, void *y); void *first (tuple t); void *second (tuple t); int equals (tuple t1, tuple t2); …
“tuple” Interface// in file “tuple.h”#ifndef TUPLE_H#define TUPLE_H
typedef void *poly;typedef struct tuple *tuple;
tuple newTuple (poly x, poly y);poly first (tuple t);poly second (tuple t);int equals (tuple t1, tuple t2);
#endif TUPLE_H
Client Code// in file “main.c”#include “complex.h”#include “nat.h”#include “tuple.h”int main (){ complex c = newComplex (1.0, 2.0); nat n1 = newNat (8); nat n2 = newNat (6);
tuple t1 = newTuple (n1, c); tuple t2 = newTuple (n2, c); return 0;}
“tuple” ADT Implementation// in file “tuple.c”#include <stdlib.h>#include “tuple.h”
struct tuple{ poly x; poly y;};tuple newTuple (poly x, poly y){ tuple t = malloc (sizeof (*t)); t->x = x; t->y = y; return t;}
x
y
t
“tuple” ADT Implementation// in file “tuple.c”#include <stdlib.h>#include “tuple.h”
struct tuple{ poly x; poly y;};
poly first (tuple t){ return t->x;}
x
y
t
Client Code// in file “main.c”#include “complex.h”#include “nat.h”#include “tuple.h”int main (){ complex c = newComplex (1.0, 2.0); nat n1 = newNat (8); nat n2 = newNat (6); tuple t1 = newTuple (n1, c); tuple t2 = newTuple (n2, c); nat temp = (nat)first (t1); // type cast return 0;}
“equals”?struct tuple{ poly x; poly y;};
// The first try:int equals (tuple t1, tuple t2){ return ((t1->x) == (t2->x) && (t1->y) == (t2->y)) // Wrong!!}
“equals”?struct tuple{ poly x; poly y;};
// The second try:int equals (tuple t1, tuple t2){ return (equalsXXX (t1->x, t2->x) && equalsYYY (t1->y, t2->y)) // but what are “equalsXXX” and “equalsYYY”?}
Function as Arguments// So instead of guessing the types of t->x and // t->y in the body of “equals” function, we // require the callers of “equals” supply the // necessary equality testing functions. // The second try:// typedef int (*fun)(poly, poly);
int equals (tuple t1, tuple t2, fun eqx, fun eqy){ return (eqx (t1->x, t2->x) && eqy (t1->y, t2->y));}
Change to “tuple” Interface// in file “tuple.h”#ifndef TUPLE_H#define TUPLE_H
typedef void *poly;typedef int (*fun)(poly, poly);typedef struct tuple *tuple;
tuple newTuple (poly x, poly y);poly first (tuple t);poly second (tuple t);int equals (tuple t1, tuple t2, fun eqx, fun eqy);
#endif TUPLE_H
Client Code// in file “main.c”#include “complex.h”#include “nat.h”#include “tuple.h”int main (){ complex c = newComplex (1.0, 2.0); nat n1 = newNat (8); nat n2 = newNat (6); tuple t1 = newTuple (n1, c); tuple t2 = newTuple (n2, c); equals (t1, t2, natEquals, complexEquals); return 0;}
Moral void* serves as polymorphic type in C
mask all pointer types (think Object type in Java) Pros:
code reuse: write once, used in arbitrary context we’d see more examples later in this course
Cons: Polymorphism doesn’t come for free
boxed data: data heap-allocated (to cope with void *) no static or runtime checking (at least in C) clumsy code
extra function pointer arguments
Function Pointer in Datatypedef int (*fun)(poly, poly);int equals (tuple t1, tuple t2){ // note that if t1->x or t1->y has carried the // equality testing functions, then the code // could just be written: return (t1->x->equals (t1->x, t2->x) && t1->y->equals (t1->y,t2->y)); }
……
equals
x
y
t1
t1->x
Function Pointer in Data// To cope with this, we should modify other // modules. For instance, the “nat” ADT:struct nat{ int (*equals) (poly, poly); int i;};
nat newNat (int i){ nat n = malloc (sizeof (*n)); n->equals = natEquals; n->i = i; return n;}
i
n
equals
The Calltypedef int (*fun)(poly, poly);int equals (tuple t1, tuple t2){ return (t1->x->equals (t1->x, t2->x) && t1->y->equals (t1->y,t2->y));}
i
t1->x
equals
i
t2->x
Client Code// in file “main.c”#include “complex.h”#include “nat.h”#include “tuple.h”int main (){ complex c = newComplex (1.0, 2.0); nat n1 = newNat (8); nat n2 = newNat (6); tuple t1 = newTuple (n1, c); tuple t2 = newTuple (n2, c); equals (t1, t2); // dirty simple! :-P return 0;}
Function Pointers in Data
Data elements with function pointers is the simplest form of objects object = virtual functions + private data
With such facilities, we can in principal model object programming In fact, early C++ compilers compiles to C That’s partly why I don’t love object-o
riented languages
Summary Data structure studies data representation and
operations direct interplay with algorithm design
Abstract data types enable modular programming
clear separation between interface and implementation
interface and implementation should design and evolve together
Polymorphism enables code reuse See the course web page for programming
assignments