Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Extensible Array C and Data Structures Baojian Hua [email protected] Data Structures Data structure studies the organization of data in computers, consisting of Algorithms: the (abstract) data types (definition and repr’) relationship between elements of this type operations on data types operations on data structures subtle interplay with data structure design Slogan: program=data structures + algorithm What will this part cover? Linear structures: Tree & forest: extensible array, linked list, stack, queue, string, etc. binary tree, binary search tree Graph Hash Sorting and Searching? Linear Data Structures A linear list (list) consists of: a collection of data elements elements are ordered: e1, e2, …, en (n≥0) e1≤e2≤ … ≤en ei is called an predecessor of ei+1 ei+1 is called a successor of ei every element has at most one successor and one predecessor Typical operations // create an empty list new (); // the length of a list l length (list l); // insert element x at position i in l, 0<=i<n insert (list l, x, i); // return the i-th element nth (list l, i); // delete the element at position i in l, 0<=i<n delete (list l, i); // apply function f to each element in l foreach (list l, f); Polymorphic Abstract Data Types in C // in “list.h” #ifndef LIST_H #define LIST_H typedef struct List_t *List_t; List_t List_new (); int List_length (List_t l); poly List_nth (List_t l, int n); // “poly”? void List_insert (List_t l, poly x, int i); poly List_delete (List_t l, int i); void List_foreach (List_t l, void (*f)(poly)); #endif Implementations Two well-known 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 0 n-1 and the array may not be full, so we must keep a “tail” tag to record its tail (the position of its last elements) Implementation Using Array The straightforward method to implement this interface is to use an array tail 0 n-1 and the array may not be full, so we must keep a “tail” tag to record its tail (the position of its last elements) 1st Try #define N 100 int main () { int a[N]; int tail = 0; tail 0 n-1 a[tail++] = 3; a[tail++] = 5; … // what if we continue to insert value into “a”? } Array-based Implementation // Combine these above observations, we have: // in file “arrayList.c” #include <stdlib.h> #include “list.h” #define INIT_LENGTH 32 l #define EXT_FACTOR 2 struct List_t { poly *array; int max; int tail; }; array max tail 0 n-1 Create an Empty List List_t List_new () { List_t l = malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l->tail = 0; return l; } Create an Empty List List_t List_new () { List_t l = malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l->tail = 0; return l; } l $#%& %$&^ @#%$ Create an Empty List List_t List_new () { List_t l = malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH; l l->tail = 0; array %$&^ return l; @#%$ } 0 n-1 Create an Empty List List_t List_new () { List_t l = malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH ; l l->tail = 0; array return l; } max @#%$ 0 n-1 Create an Empty List List_t List_new () { List_t l = malloc (sizeof (*l)); l->array = malloc (INIT_LENTH * sizeof(poly)); l->max = INIT_LENTH ; l l->tail = 0; array return l; } max tail 0 n-1 Operation: “length” int List_length (List_t 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); l array return l->tail; max } tail 0 n-1 Operation: “nth” poly List_nth (List_t l, int i) { if (i<0 || i>=l->tail) error (“invalid index”); return (l->array)[i]; } l array max tail 0 n-1 Operation: “nth” poly List_nth (List_t l, int i) { if (i<0 || i>=l->tail) error (“invalid index”); return (l->array)[i]; } l array max tail i 0 temp n-1 Operation: “insert” void List_insert (List_t l, poly x, int i) { if (i<0 || i>l->tail) error (“invalid index”); //move the data …; } l array max tail i 0 n-1 Operation: “insert” void List_insert (List_t l, poly x, int i) { if (i<0 || i>l->tail) error (“invalid index”); l for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …; array max tail i } 0 j n-1 Operation: “insert” void List_insert (List_t l, poly x, int i) { if (i<0 || i>l->tail) error (“invalid index”); l for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …; array max tail i } 0 j n-1 Operation: “insert” void List_insert (List_t l, poly x, int i) { if (i<0 || i>l->tail) error (“invalid index”); l for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; …; array max tail i } 0 j n-1 Operation: “insert” void List_insert (List_t l, void *x, int i) { if (i<0 || i>l->tail) error (“invalid index”); l for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; (l->array)[i] = x; array max tail i x } 0 j n-1 Operation: “insert” void List_insert (list l, void *x, int i) { if (i<0 || i>l->tail) error (“invalid index”); l for (int j=l->tail; j>i; j--) (l->array)[j] = (l->array)[j-1]; (l->array)[i] = x; (l->tail)++; array max tail i x } 0 j n-1 Perfect? What if the initial array look like the right one? direct data movement will incur an out-ofbound error! l array max tail i 0 n-1 Extensible Array void List_insert (List_t 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 l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly)); l array max tail i 0 0 i n-1 n-1 2n-1 Extensible Array l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly)); l array max tail i 0 0 n-1 i n-1 2n-1 Extensible Array l->array = realloc (l->array, EXT_FACTOR*(l->max)*sizeof(poly)); l array l->max *= EXT_FACTOR; max tail i 0 0 i n-1 2n-1 Extensible Array l array max tail i 0 n-1 2n-1 Operation: “delete” The “delete” operation is reverse operation of the “insert” also involves data movement should we shrink the extensible array, when there are few elements in it (say ½ data item left)? More tricky than first looks Operation: “foreach” void List_foreach (List_t l, void (*f)(poly)) { for (int i=0; i<l->tail; i++) f ((l->array)[i]); return; l array } max tail 0 n-1 Summary Linear list ADT: a collection of ordered data element each item has no more than one successor or predecessor Extensible array-based implementation maintain internally a dynamically extensible array bad performance with insert or delete space waste