abstract data type
Download
Skip this Video
Download Presentation
Abstract Data Type

Loading in 2 Seconds...

play fullscreen
1 / 48

Abstract Data Type - PowerPoint PPT Presentation


  • 122 Views
  • Uploaded on

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: any language defines a group of predefined data types

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Abstract Data Type' - gabriel-albert


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
abstract data type

Abstract Data Type

C and Data Structures

Baojian Hua

[email protected]

data types
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
      • C e.g.: int, char, float, double, …
    • user-defined:
      • allow programmers to define their own (new) data types
      • C e.g.: struct, union, …
data type examples
Data Type Examples
  • Predefined:
    • type: int
    • elements: …, -2, -1, 0, 1, 2, …
    • operations: +, -, *, /, %, …
  • User-defined:
    • type: complex
    • elements: 1+3i, -5+8i, …
    • operations: new, add, sub, distance, …
concrete data types cdt
Concrete Data Types (CDT)
  • An concrete data type:
    • both concrete representations and their operations are available
  • Almost all C predefined types are CDT
    • For instance, “int” is a 32-bit double-word, and +, -, …
    • Knowing this can do dirty hacks
    • See demo…
abstract data types adt
Abstract Data Types (ADT)
  • An abstract data type:
    • separates data type declaration from representation
    • separates function declaration (prototypes) from implementation (definitions)
  • A language must some form of mechanism to support ADT
    • interfaces in Java
    • signatures in ML
    • (roughly) header files & typedef in C
case study
Case Study
  • Suppose we’d design a new data type to represent complex number c:
    • a data type “complex”
    • elements: 3+4i, -5-8i, …
    • operations:
      • new, add, sub, distance, …
  • How to represent this data type in C (CDT, ADT or …)?
complex number
Complex Number

// Recall the definition of a complex number c:

c = x + yi, where x,y \in R, and i=sqrt(-1);

// Some typical operations:

complex Complex_new (double x, double y);

complex Complex_add (complex c1, complex c2);

complex Complex_sub (complex c1, complex c2);

complex Complex_mult (complex c1, complex c2);

complex Complex_divide (complex c1, complex c2);

// Next, we’d discuss several variants of rep’s:

// CDT, ADT.

cdt of complex interface types
CDT of Complex:Interface—Types

// In file “complex.h”:

#ifndef COMPLEX_H

#define COMPLEX_H

struct Complex_t

{

double x;

double y;

};

typedef struct Complex_t Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif

client code
Client Code

// With this interface, we can write client codes

// that manipulate complex numbers. File “main.c”:

#include “complex.h”

int main ()

{

Complex_t c1, c2, c3;

c1 = Complex_new (3.0, 4.0);

c2 = Complex_new (7.0, 6.0);

c3 = Complex_add (c1, c2);

Complex_output (c3);

return 0;

}

Do we know c1, c2, c3’s concrete representation?

How?

cdt complex implementation
CDT Complex: Implementation

// In a file “complex.c”:

#include “complex.h”

Complex_t Complex_new (double x, double y)

{

Complex_t c = {.x = x, .y = y};

return c;

}

// other functions are similar. See Lab1

problem 1
Problem #1

int main ()

{

Complex_t c;

c = Complex_new (3.0, 4.0);

// Want to do this: c = c + (5+i6);

// Ooooops, this is legal:

c.x += 5;

c.y += 6;

return 0;

}

problem 2
Problem #2

#ifndef COMPLEX_H

#define COMPLEX_H

struct Complex_t

{

// change to a more fancy one? Anger “main”…

double a[2];

};

typedef struct Complex_t Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif

problems with cdt
Problems with CDT?
  • Operations are transparent.
    • user code have no idea of the algorithm
    • Good!
  • Data representations dependence
    • Problem #1: Client code can access data directly
      • kick away the interface
      • safe?
    • Problem #2: make code rigid
      • easy to change or evolve?
adt of complex interface types
ADT of Complex:Interface—Types

// In file “complex.h”:

#ifndef COMPLEX_H

#define COMPLEX_H

// note that “struct complexStruct” not given

typedef struct Complex_t *Complex_t;

Complex_t Complex_new (double x, double y);

// other function prototypes are similar

#endif

client code1
Client Code

// With this interface, we can write client codes

// that manipulate complex numbers. File “main.c”:

#include “complex.h”

int main ()

{

Complex_t c1, c2, c3;

c1 = Complex_new (3.0, 4.0);

c2 = Complex_new (7.0, 6.0);

c3 = Complex_add (c1, c2);

Complex_output (c3);

return 0;

}

Can we still know c1, c2, c3’s concrete representation?

Why?

adt complex implementation 1 types
ADT Complex: Implementation#1—Types

// In a file “complex.c”:

#include “complex.h”

// We may choose to define complex type as:

struct Complex_t

{

double x;

double y;

};

// which is hidden in implementation.

adt complex implementation continued
ADT Complex: Implementation Continued

// In a file “complex.c”:

#include “complex.h”

Complex_t Complex_new (double x, double y)

{

Complex_t c;

c = malloc (sizeof (*c));

c->x = x;

c->y = y;

return c;

}

// other functions are similar. See Lab1

adt summary
ADT Summary
  • Yes, that’s ADT!
    • Algorithm is hidden
    • Data representation is hidden
      • client code can NOT access it
      • thus, client code independent of the impl’
  • Interface and implementation
  • Do Lab1
polymorphism
Polymorphism
  • To explain polymorphism, we start with a new data type “tuple”
  • A tuple is of the form: (x, y)
    • xA, yB (aka: A*B)
    • A, B may be unknown in advance and may be different
  • E.g:
    • A=int, B=int:
      • (2, 3), (4, 6), (9, 7), …
    • A=char *, B=double:
      • (“Bob”, 145.8), (“Alice”, 90.5), …
polymorphism1
Polymorphism
  • From the data type point of view, two types:
    • A, B
  • operations:
    • new (x, y); // create a new tuple with x and y
    • equals (t1, t2); // equality testing
    • first (t); // get the first element of t
    • second (t); // get the second element of t
  • How to represent this type in computers (using C)?
monomorphic version
Monomorphic Version
  • We start by studying a monomorphic tuple type called “intTuple”:
    • both the first and second components are of “int” type
    • (2, 3), (8, 9), …
  • The intTuple ADT:
    • type: intTuple
    • elements: (2, 3), (8, 9), …
    • Operations:
      • tuple new (int x, int y);
      • int first (int t);
      • int second (tuple t);
      • int equals (tuple t1, tuple t2);
inttuple cdt
“IntTuple” CDT

// in a file “int-tuple.h”

#ifndef INT_TUPLE_H

#define INT_TUPLE_H

struct IntTuple_t

{

int x;

int y;

};

typedef struct IntTuple_t IntTuple_t;

IntTuple_t IntTuple_new (int n1, int n2);

int IntTuple_first (IntTuple_t t);

#endif

or the inttuple adt
Or the “IntTuple” ADT

// in a file “int-tuple.h”

#ifndef INT_TUPLE_H

#define INT_TUPLE_H

typedef struct IntTuple_t *IntTuple_t;

IntTuple_t IntTuple_new (int n1, int n2);

int IntTuple_first (IntTuple_t t);

int IntTuple_equals (IntTuple_t t1,

IntTuple_t t2);

#endif

// We only discuss “tupleEquals ()”. All others

// functions left to you.

equality testing
t1

t2

x

x

y

y

Equality Testing

// in a file “int-tuple.c”

int Tuple_equals (IntTuple_t t1, IntTuple_t t2)

{

return ((t1->x == t2->x) && (t1->y==t2->y));

}

problems
Problems?
  • It’s ok if we only design “IntTuple”
  • But we if we’ll design these tuples:
    • (int, double), (int, char *), (double, double), …
  • Same code exists everywhere, no means to maintain and evolve
    • Nightmares for programmers
    • Remember: never duplicate code!
polymorphism2
Polymorphism
  • Now, we consider a polymorphic tuple type called “tuple”:
    • “poly”: may take various forms
    • Every element of the type “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
The Tuple ADT
  • What about operations?
    • tuple new (??? x, ??? y);
    • ??? first (tuple t);
    • ??? second (tuple t);
    • int equals (tuple t1, tuple t2);
polymorphic type
Polymorphic Type
  • To resove this, C dedicates a special polymorphic type “void *”
    • “void *” is a pointer which can point to “any” concrete types (i.e., it’s compatible with any pointer type),
      • very poly…
    • long history of practice, initially “char *”
    • can not be used directly, use ugly cast
    • similar to constructs in others language, such as “Object”
the tuple adt1
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
“tuple” Interface

// in a file “tuple.h”

#ifndef TUPLE_H

#define TUPLE_H

typedef void *poly;

typedef struct Tuple_t * Tuple_t;

Tuple_t Tuple_new (poly x, poly y);

poly first (Tuple_t t);

poly second (Tuple_t t);

int equals (Tuple_t t1, Tuple_t t2);

#endif TUPLE_H

client code2
Client Code

// file “main.c”

#include “tuple.h”

int main ()

{

int i = 8;

Tuple_t t1 = Tuple_new (&i, “hello”);

return 0;

}

tuple adt implementation
t

x

y

“tuple” ADT Implementation

// in a file “tuple.c”

#include

#include “tuple.h”

struct Tuple_t

{

poly x;

poly y;

};

Tuple_t Tuple_new (poly x, poly y)

{

tuple t = malloc (sizeof (*t));

t->x = x;

t->y = y;

return t;

}

tuple adt implementation1
t

x

y

“tuple” ADT Implementation

// in a file “tuple.c”

#include

#include “tuple.h”

struct Tuple_t

{

poly x;

poly y;

};

poly Tuple_first (Tuple_t t)

{

return t->x;

}

client code3
Client Code

#include “complex.h” // ADT version

#include “tuple.h”

int main ()

{

int i = 8;

Tuple_t t1 = Tuple_new (&i, “hello”);

// type cast

int *p = (int *)Tuple_first (t1);

return 0;

}

equality testing1
t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #1 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return ((t1->x == t2->x)

&& (t1->y == t2->y));

// Wrong!!

}

equality testing2
t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #2 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return (*(t1->x) == *(t2->x)

&& *(t1->y) == *(t2->y));

// Problem?

}

equality testing3
t

x

y

Equality Testing

struct Tuple_t

{

poly x;

poly y;

};

// The #3 try:

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return (equalsXXX(t1->x, t2->x)

&&equalsYYY(t1->y, t2->y));

// but what are “equalsXXX” and “equalsYYY”?

}

function as arguments
Function as Arguments

// So in the body of “equals” function, instead

// of guessing the types of t->x and t->y, we

// require the callers of “equals” supply the

// necessary equality testing functions.

// The #4 try:

typedef int (*tf)(poly, poly);

int Tuple_equals (tuple t1, tuple t2,

tf eqx, tf eqy)

{

return(eqx (t1->x, t2->x)

&&eqy (t1->y, t2->y));

}

change to tuple interface
Change to “tuple” Interface

// in file “tuple.h”

#ifndef TUPLE_H

#define TUPLE_H

typedef void *poly;

typedef int (*tf)(poly, poly);

typedef struct Tuple_t *Tuple_t;

Tuple_t Tuple_new (poly x, poly y);

poly Tuple_first (Tuple_t t);

poly Tuple_second (Tuple_t t);

int Tuple_equals (Tuple_t t1, Tuple_t t2,

tf eqx, tf eqy);

#endif TUPLE_H

client code4
Client Code

// in file “main.c”

#include “tuple.h”

int main ()

{

int i=8, j=8, k=7, m=7;

Tuple_t t1 = Tuple_new (&i, &k);

Tuple_t t2 = Tuple_new (&j, &k);

Tuple_equals (t1, t2, Int_equals, Int_equals);

return 0;

}

moral
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 carrying data
Function-Carrying Data
  • Why we can NOT make use of data, such as passed as function arguments, when it’s of type “void *”?
  • Better idea:
    • Let data carry functions themselves, instead passing function pointers
    • such kind of data called objects
function pointer in data
Function Pointer in Data

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

// note that if t1->x or t1->y has carried the

//equality testing functions, thenthe code

// could just be written as:

return (t1->x->equals (t1->x, t2->x)

&& t1->y->equals (t1->y, t2->y));

}

equals

equals_x

……

t1

x

equals_y

y

equals

……

function pointer in data1
equals

n

x

y

Function Pointer in Data

// To cope with this, we should modify other

// modules. For instance, the “complex” ADT:

struct Complex_t

{

int (*equals) (poly, poly);

double a[2];

};

Complex_t Complex_new (double x, double y)

{

Complex_t c = malloc (sizeof (*c));

c->equals = Complex_equals;

…;

return n;

}

function call
Function Call

int Tuple_equals (Tuple_t t1, Tuple_t t2)

{

return(t1->x->equals (t1->x, t2->x)

&& t1->y->equals (t1->y,t2->y));

}

equals

t2

t1

x

a[0]

a[0]

x

y

a[1]

a[1]

y

client code5
Client Code

// in file “main.c”

#include “complex.h”

#include “tuple.h”

int main ()

{

Complex_t c1 = Complex_new (1.0, 2.0);

Complex_t c2 = Complex_new (1.0, 2.0);

Tuple_t t1 = Tuple_new (c1, c2);

Tuple_t t2 = Tuple_new (c1, c2);

Tuple_equals (t1, t2); // dirty simple! :-P

return 0;

}

object
Object
  • 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 oriented programming
    • In fact, early C++ compilers compiles to C
    • That’s partly why I don’t love object-oriented languages
summary
Summary
  • Abstract data types enable modular programming
    • clear separation between interface and implementation
    • interface and implementation should design and evolve together
  • Polymorphism enables code reuse
  • Object = data + function pointers
ad