extensible array
DESCRIPTION
Extensible Array. C and Data Structures Baojian Hua [email protected]. Linear Data Structures. A linear list (list) consists of: a collection of data elements e1, e2, … , en elements are ordered: e1 ≤ e2 ≤ … ≤ en ei is called an predecessor of e_{i+1} - PowerPoint PPT PresentationTRANSCRIPT
Linear Data Structures A linear list (list) consists of:
a collection of data elements e1, e2, …, en
elements are ordered: e1≤e2 ≤ … ≤ en
ei is called an predecessor of e_{i+1} e_{i+1} is called a successor of ei every element has at most one successor
and one predecessor
Linear Data Structures Typical operations on linear list :// create an empty listnewList ();// the length of a list llength (list l); // insert element x at position i in l, 0<=i<ninsert (list l, x, i); // return the i-th elementnth (list l, i); // delete the element at position i in l, 0<=i<ndelete (list l, i);// apply function f to each element in lforeach (list l, f);
Polymorphic Abstract Data Types in C// in “list.h”
#ifndef LIST_H
#define LIST_H
typedef struct listStruct *list;
list newList ();
int length (list l);
poly nth (list l, int n); // “poly”?
void insert (list l, poly x, int i);
poly delete (list l, int i);
void foreach (list l, void (*f)(poly));
#endif
Implementations
Two typical implementation techniques: array-based linked structure-based
We next consider the first, and leave the second to the next slide
Implementation Using Array The straightforward method to
implement this interface (ADT) is to use an array
and the array may not be full, so we must keep a “tail” tag to record its tail (the position of its last elements)
0 n-1
Implementation Using Array The straightforward method to implement
this interface is to use an array
and the array may not be full, so we must keep a “tail” tag to record its tail (the position of its last elements)
0 n-1
tail
Array-based Implementation// Combine these above observations, we have:// in file “arrayList.c”#include <stdlib.h>#include “list.h”
#define INIT_LENGTH 32#define EXT_FACTOR 2
struct listStruct{ poly *array;
int max; int tail;};
0 n-1
array
max
tail
l
Operation: “newList”list newList (){ list l = (list)malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l->tail = 0;
return l;}
Operation: “newList”list newList (){ list l = (list)malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l->tail = 0;
return l;}
$#%&
%$&^
@#%$
l
Operation: “newList”list newList (){ list l = (list)malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l->tail = 0;
return l;}
0 n-1
array
%$&^
@#%$
l
Operation: “newList”list newList (){ list l = (list)malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH ; l->tail = 0;
return l;}
0 n-1
array
max
@#%$
l
Operation: “newList”list newList (){ list l = (list)malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH ; l->tail = 0;
return l;}
0 n-1
array
max
tail
l
Operation: “length”int length (list l){ // note that we omit such checks in the next // for clarity. However, You should always do
// such kind of checks in your code. assert(l); return l->tail;}
0 n-1
array
max
tail
l
Operation: “nth”poly nth (list l, int i){ if (i<0 || i>=l->tail) error (“invalid index”);
poly temp; temp = *((l->array)+i); return temp;}
0 n-1
array
max
tail
l
Operation: “nth”poly nth (list l, int i){ if (i<0 || i>=l->tail) error (“invalid index”);
poly temp; temp = *((l->array)+i); return temp;}
0 n-1
array
max
tail
l
i
temp
Operation: “insert”void insert (list l, poly x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
//move the data …;}
0 n-1
array
max
tail
l
i
Operation: “insert”void insert (list l, poly x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …;}
0 n-1
array
max
tail
l
i
j
Operation: “insert”void insert (list l, poly x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …;}
0 n-1
array
max
tail
l
i
j
Operation: “insert”void insert (list l, poly x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …;}
0 n-1
array
max
tail
l
i
j
Operation: “insert”void insert (list l, void *x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; (l->array)[i] = x;}
x
0 n-1
array
max
tail
l
i
j
Operation: “insert”void insert (list l, void *x, int i){ if (i<0 || i>l->tail) error (“invalid index”);
for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; (l->array)[i] = x; (l->tail)++;} x
0 n-1
array
max
tail
l
i
j
Perfect? What if the initial input arguments
look like this one? direct datamovement willincur an out-of-bound error!
0 n-1
array
max
tail
l
i
Extensible Arrayvoid insert (list l, poly x, int i){ if (i<0 || i>l->tail) error (“invalid index”); // if l is full, extend l->array by a factor… if (l->tail==l->max) { l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly)); l->max *= EXT_FACTOR; } // data movement as discussed above…;}
Extensible Array
0 n-1
array
max
tail
l
i
0 2n-1
i
l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly));
n-1
Extensible Array
0 n-1
array
max
tail
l
i
0 2n-1
i
n-1
l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly));
Extensible Array
0 n-1
array
max
tail
l
i
0 2n-1
i
l->max *= EXT_FACTOR;
l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly));
Operation: “delete”
The “delete” operation is reverse operation of the “insert” operation also involves data movement should we shrink the extensible array,
when there are few elements in it (say ½ data item left)?
See the programming assignment
Operation: “foreach”void foreach (list l, void (*f)(poly)){ for (int i=0; i<l->tail; i++) f (*(l->array + i)); return;}
0 n-1
array
max
tail
l