510 likes | 796 Views
Data Structure & Abstract Data Type. C and Data Structures Baojian Hua bjhua@ustc.edu.cn. 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:
E N D
Data Structure &Abstract Data Type C and Data Structures Baojian Hua bjhua@ustc.edu.cn
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 types • (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 data 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; }
n i “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; }
n i “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; }
n1 n2 n i i n1->i + n2->i “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; }
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 different • 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 called “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; }
t n1 n2 “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; }
t n1 n2 “natTuple” Implementation // in file “natTuple.c” #include “natTuple.h” struct natTuple { nat n1; nat n2; }; nat first (natTuple t) { return t->n1; }
t1 t2 n1 n1 n2 n2 “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); }
t1 t2 n1 n1 n2 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)); }
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
n1 n2 i i 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); }
t1 t2 n1 n1 n2 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)); }
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; }
t x y “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; }
t x y “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; }
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
equals t1->x …… t1 x y Function Pointer in Data typedef int (*fun)(poly, poly); int equals (tuple t1, tuple t2) { // note that if t1->x or t1->y has carried the //equality testing functions, thenthe code // could just be written: return (t1->x->equals (t1->x, t2->x) && t1->y->equals (t1->y,t2->y)); }
equals n i 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; }
equals t2->x t1->x i i The Call typedef 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)); }
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-oriented 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