340 likes | 484 Views
Linked List. C and Data Structures Baojian Hua bjhua@ustc.edu.cn. Recap. The extensible array-based implementation of linear list: may be too slow insert or delete operations involve data movement may be too space waste only a small portion of the allocated space is occupied with data
E N D
Linked List C and Data Structures Baojian Hua bjhua@ustc.edu.cn
Recap • The extensible array-based implementation of linear list: • may be too slow • insert or delete operations involve data movement • may be too space waste • only a small portion of the allocated space is occupied with data • General computer science idea • “pay as you go”
Polymorphic Abstract Data Types in C // recall the poly ADT: #ifndef LIST_H #define LIST_H typedef void *poly; typedef struct listStruct *list; list newList (); int length (list l); poly nth (list l, int n); void insert (list l, poly x, int i); poly delete (list l, int i); void foreach (list l, void (*f)(poly)); #endif
head … Implementation Using Linked List • Linked list is a self-reference structure: • to simplify operations, we add a unique head node “head” • “head” does not belong to the list • may hold meta information of the list
head … data data data next next next Linked List-based Implementation // Turn the above figure into C, we have: // in file “linkedList.c” #include <stdlib.h> #include “list.h” struct listStruct { poly data; list next; };
/\ /\ l Operation: “newList” // “new” returns an empty list, which consists of // a single head node. list newList () { list l = (list)malloc (sizeof (*l)); l->data = NULL; // Why this? l->next = NULL; return l; }
l … data data data next next next Operation: “length” int length (list l) { list p = l->next; int n = 0; while (p) { p = p->next; n++; } return n; } n==0 p
l … data data data next next next Operation: “length” int length (list l) { list p = l->next; int n = 0; while (p) { p = p->next; n++; } return n; } n==1 p
l … data data data next next next Operation: “length” int length (list l) { list p = l->next; int n = 0; while (p) { p = p->next; n++; } return n; } n==2 p
l … data data data next next next Operation: “length” int length (list l) { list p = l->next; int n = 0; while (p) { p = p->next; n++; } return n; } n==3 p
Operation: “nth” poly nth (list l, int n) { list p = l->next; int i = 0; if (n<0 || n>=length(l)) error (“invalid index”); while (i!=n) { p = p->next; i++; } return p; }
l l l … … … data data data data data data data data data next next next next next next next next next Operation: “nth” n==2 i==0 p n==2 i==1 p n==2 i==2 p
data data data x next next next next we’d search pointer p Operation: “insert” void insert (list l, poly x, int n) { // 1. change the “next” field of pointer t; // 2. change the “next” field of element (n-1) …; } n==2 l … t
Operation: “insert” void insert (list l, poly x, int n) { list p; if (n<0 || n>length(l)) error (“invalid index”); // search pointer p points to position n-1 p = n? (nth (l, n-1)) : l;
Operation: “insert” // continued… // Step #1: cook list node: list temp = (list)malloc (sizeof (*temp)); temp->data = x; // Step #2: temp points to n-th data item temp->next = p->next; // Step #3: link temp onto list p->next = temp; return; }
data data data next next next we’d search pointer p Operation: “delete” poly delete (list l, int n) { // The key step is to search pointer p // Leave this as exercise. // See Lab #3. …; } n==2 l …
data data data next next next Operation: “foreach” void foreach (list l, void (*f)(poly)) { list p = l->next; while (p) { f (p->data); p = p->next; } } l …
Linked List Summary • Linked list: • better space usage---no waste • good time complexity • insert or delete take linear time • but have to search the data sequential, :-( • Can be further generalized: • circular linked list • doubly linked list • doubly circular linked list
head data data data tail next next next Circular Linked List • All the pointers forms a circle • Note that the first node has two fields • head: points to the head of the list • tail: points to the tail of the list l
head data data data l tail next next next Circular Linked List---Implementation // in file “clist.c” struct listStruct { struct node *head; struct node *tail; }; struct node { poly data; struct node *next; }
Linear List Application #1: Polynomials • Polynomials: • where ciR and n Nat • uniquely determined by a linear list: • For this representation, all the list operations apply
Linear List Application: Polynomials • Space waste: • Consider this: • 20001 items with 3 non-zeros • A refined representation: • ci<>0 for 0<=i<=m • Ex:
Polynomial ADT: Interface • Abstract data type: polyn • represent the polynomial data type • operations: polyn newPolyn (); // an empty polyn polyn add (polyn p1, polyn p2); real value (polyn p, real x0); // p(x0) polyn mult (polyn p1, polyn p2); // add an item c*x^n, which does not appear in p void insert (polyn p, real c, int n);
Polynomial ADT in C: Interface // in file “polyn.h” #ifndef POLYN_H #define POLYN_H typedef struct polynStruct *polyn; polyn newPolyn (); polyn add (polyn p1, polyn p2); real value (polyn p, real x0); polyn mult (polyn p1, polyn p2); void insert (polyn p, real c, int n); #endif
Polynomial ADT in C: Implementation // in file “polyn.c” #include “linkedList.h” #include “polyn.h” struct polynStruct { linkedList coefExps; }; // where “coefExps” is a list of tuples: (c, n) // one way to read “list coefExps” is: // list<tuple<double, nat>> coefExps // However, C does not support this style of // declaration… :-(
Operation: “newPolyn” polyn newPolyn () { polyn p = (polyn)malloc (sizeof (*p)); // use a linked list internally p->coefExps = newLinkedList (); return p; }
Operation: “insert” void insert (polyn p, real c, nat n) { // could we use “double” and “int”, instead of // “real” and “nat”? tuple t = newTuple (c, n); linkedListInsertAtTail (p->coefExps, t); return; } // Leave other functions as exercises.
Change to the Head #include <stdlib.h> #include “linkedList.h” #include “tuple.h” #include “polyn.h” struct polyn { linkedList coefExps; };
Linear List Application#2: Dictionary • Dictionay: • where ki are keys and vi are value • all ki are comparable and distinct • How can dict’ be represented in computers? • many ideas (we’d discuss some in future) • for now, we make use of a linear list
Dictionary ADT: Interface • Abstract data type: dict • represent the dictionary data type • operations: dict newDict (); // an empty dict void insert (dict d, poly key, poly value); poly lookup (dict d, poly key); poly delete (dict d, poly key);
“dict” ADT in C: Interface // in file “dict.h” #ifndef DICT_H #define DICT_H typedef struct dictStruct *dict; dict newDict (); void insert (dict d, poly key, poly value); poly lookup (dict d, poly key); poly delete (dict d, poly key); #endif
“dict” ADT in C: Implementation // in file “dict.c” #include “linkedList.h” #include “dict.h” struct dictStruct { linkedList l; };
Operations: “new” dict newDict () { dict d = (dict)malloc (sizeof (*d)); d->l = newLinkedList (); return d; }
Operations: “insert” void insert (dict d, poly key, poly value) { tuple t = newTuple (key, value); linkedListInsertAtHead (d->l, t); return; } // Leave other functions as programming // exercises.