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
Dynamically Extensible Data Structures Discrete Mathematics and Its Applications Baojian Hua [email protected] Information Association In processing data structures, one often need to associate information with some kind of items Examples from graphs: Vertex: data, value, degree (in, out), … Edge: weight, … BFS: visited, distance, …, DFS: visited, discover, finish, … MST: tree edges, … Dijkstra: tree edges, … … Several Methods Monomorphic data in item Polymorphic data in item Auxiliary table (dictionary) Dynamically extensible space in item Next, I’ll take DFS as a running example Graph Representation: Adjacency List #include “linkedList.h” #include “graph.h” struct graph { linkedList vertices; }; typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { 0 poly data; linkedList edges; 1 }; struct edge { vertex from; 2 vertex to; } 3 0->1 0->2 0->3 DFS Algorithm dfs (vertex start, tyVisit visit) { visit (start); for (each adjacent vertex u of “start”) if (not visited u) // but how do we know? dfs (u, visit); } DFS Algorithm void dfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); dfs (startV, visit); for (each vertex u in graph g) if (not visited u) // but how do we know? dfs (u, visit); } Method #1: Monomorphic Data in Vertex #include “linkedList.h” #include “graph.h” struct graph { linkedList vertices; }; typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { 0 poly data; int visited; // a flag 1 linkedList edges; }; struct edge { 2 vertex from; vertex to; 3 0->1 0->2 0->3 Adjacency List-based: Creating New Vertex vertex newVertex (poly data) { vertex v = malloc (sizeof (*v)); v->data = data; v->visited = 0; v->edges = newLinkedList (); return v; } v data data visited=0 edges ### /\ DFS Algorithm dfs (vertex start, tyVisit visit) { visit (start); start->visited = 1; for (each adjacent vertex u of “start”) if (0==u->visited) // Easy! :-) dfs (u, visit); } DFS Algorithm void dfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); dfs (startV, visit); for (each vertex u in graph g) if (0==u->visited) dfs (u, visit); } Sample Graph DFS dfs (g, “a”, strOutput); a 0 b 0 c 0 d 0 e 0 f 0 Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 0 c 0 d 0 e 0 f 0 Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 1 c 0 d 0 e 0 f 0 // a choice print b; Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 1 c 0 d 0 e 1 f 0 // a choice print b; print e; Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 1 c 0 d 1 e 1 f 0 // a choice print b; print e; print d; Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 1 c 1 d 1 e 1 f 0 // a choice print b; print e; print d; // a choice print c; Sample Graph DFS dfs (g, “a”, strOutput); print a; a 1 b 1 c 1 d 1 e 1 f 1 // a choice print b; print e; print d; // a choice print c; print f; Method #2: Polymorphic Data in Vertex #include “linkedList.h” #include “graph.h” #include “poly.h” struct graph { linkedList vertices; }; typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { 0 poly data; poly visited; // a hook 1 linkedList edges; }; struct edge { 2 vertex from; vertex to;} 3 0->1 0->2 0->3 Adjacency List-based: Creating New Vertex vertex newVertex (poly data) { vertex v = malloc (sizeof (*v)); v->data = data; v->visited = newNat (0); v->edges = newLinkedList (); return v; } v data data visited edges 0 ### /\ DFS Algorithm dfs (vertex start, tyVisit visit) { visit (start); start->visited = newNat (1); for (each adjacent vertex u of “start”) if (natIsZero ((nat)(u->visited))) dfs (u, visit); } DFS Algorithm void dfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); dfs (startV, visit); for (each vertex u in graph g) if (natIsZero ((nat)(u->visited))) dfs (u, visit); } Sample Graph DFS dfs (g, “a”, strOutput); a b 0 0 d 0 c 0 e 0 f 0 Sample Graph DFS dfs (g, “a”, strOutput); a b c print a; 0 1 A garbage! A style of functional programming! 0 0 d 0 e 0 f 0 Sample Graph DFS 1 dfs (g, “a”, strOutput); a b c print a; // a choice 0 0 1 print b; 0 d 0 e 0 The rest is left as an exercise! f 0 Method #3: Auxiliary Table (Memoization) #include “linkedList.h” #include “graph.h” struct graph { linkedList vertices; }; // Data structure definitions unchanged! :-) typedef struct vertex *vertex; typedef struct edge *edge; struct vertex { 0->1 0->2 0 poly data; linkedList edges; 1 }; struct edge { vertex from; 2 vertex to; } 3 0->3 Interface for the “table” ADT // We need a table to memoize the data items that // satisfy some property. #ifndef TABLE_H #define TABLE_H typedef struct table *table; table newTable (); void tableEnter (table t, poly key, poly value); void tableLookup (table t, poly key); #endif // Implementation is any dictionary-like data // structure, such as linkedList, hash, etc. DFS Algorithm dfs (vertex start, tyVisit visit, table tb) { visit (start); tableEnter (tb, start, newNat (1)); for (each adjacent vertex u of “start”) if (tableLookup (tb, u)) dfs (u, visit, tb); } DFS Algorithm void dfsMain (graph g, poly start, tyVisit visit) { vertex startV = searchVertex (g, start); table tb = newTable (); dfs (startV, visit, tb); for (each vertex u in graph g) if (tableLookup (tb, u)) dfs (u, visit, tb); } Sample Graph DFS dfs (g, “a”, strOutput); tb a b c d e f tb = newTable(); Key (vertex) Value (nat) Sample Graph DFS dfs (g, “a”, strOutput); print a; tb a b c d e f tableEnter(tb, “a”, newNat(1)); Key (vertex) a Value (nat) 1 Sample Graph DFS dfs (g, “a”, strOutput); print a; tb a b c d e f tableLookup (tb, “b”); // ==NULL Key (vertex) a Value (nat) 1 Sample Graph DFS dfs (g, “a”, strOutput); print a; a b c d e f // a choice print b; tableEnter (tb, “b”, newNat(1)); tb The rest left to you! key (vertex) a b value (nat) 1 1 Method #4: Dynamically Extensible Space (DES) in Vertex #include “linkedList.h” #include “graph.h” #include “plist.h” 0 1 struct graph { linkedList vertices; 2 }; typedef struct vertex *vertex; typedef struct edge *edge; 3 struct vertex { poly data; plist list; // a list of hooks linkedList edges; }; struct edge { vertex from; vertex to;} 0->1 0->2 0->3 What’s a “plist”? A “plist” stands for “property list” v Property: some kind of value we care A generalization of polymorphic data fields data data plist edges ### /\ ### /\ What’s a “plist”? A “plist” stands for “property list” v it’s just a list of hooks A hook holds some property Dynamically extensible data data plist edges ### ### /\ prop1 prop2 prop3 … Sample Vertex After DFS visited==1, discover==3, finish=6; // Suppose the function adding property p to // vertex v is: attach (vertex v, poly p); // which is roughly equivalent to: linkedListInsertHead (v->plist, p); v “a” 1 3 6 data plist edges ### /\ ### Sample Vertex After DFS visited==1, discover==3, finish=6; linkedListInsertHead (v->plist, p); // the calls: attach (“a”, newNat (6)); attach (“a”, newNat (3)); attach (“a”, newNat (1)); v “a” 1 3 6 data plist edges ### /\ ### What’s a “plist”? v data Suppose we have two calls: data plist edges attach (v, newNat (1)); // discover ### /\ attach (v, newNat (6)); // finish ### /\ v data 6 1 data plist edges ### /\ ### /\ How to Find a Property? v data Suppose we have two functions: attach (v, newNat (1)); // discover attach (v, newNat (6)); // finish data plist edges ### /\ // How to find v’s finish time? ### /\ findPlist (v->plist);??? v Associate every data item with a tag (think a key). data 6 1 data plist edges ### /\ ### /\ How to Find a Property? v Modifications to attach functions: k1 = attach (v, newNat (1)); // discover k2 = attach (v, newNat (6)); // finish data data plist edges ### /\ // How to find v’s finish time? ### /\ findPlist (v, k2); // return 6 findPlist (v, k1); // return 1 v Associate every data item with a tag (think of a key). (k1, 1), (k2, 6) All ks are unique. data k2 6 k1 data plist edges ### /\ ### /\ 1 Property List Interface // In file “plist.h” #ifndef PLIST_H #define PLIST_H #include “key.h” typedef struct plist *plist; // essentially a list of tuples: (key, data) void attach (plist list, key k, poly data); poly find (plist list, key k); #endif // Implementation left to you. Representation Revisited #include “linkedList.h” #include “graph.h” #include “plist.h” 0 1 struct graph { linkedList vertices; 2 }; typedef struct vertex *vertex; typedef struct edge *edge; 3 struct vertex { poly data; plist list; // a list of hooks linkedList edges; }; struct edge { vertex from; vertex to;} 0->1 0->2 0->3 DFS with DES dfsMain (graph g, vertex start, tyVisit visit) { key visited = newKey (); dfs (start, visit, visited); for (each vertex u in graph g) if (!(find (u, visited)) dfs (u, visit, visited); } DFS with DES dfs (vertex v, tyVisit visit, key visited) { visit (v); attach (v, visited, newNat (1)); for (each successor t of v) if (!(find (t, visited))) dfs (t, visit, visited); } A Case Study: Order Statistics on Red-Black Tree Red-Black Tree in C // In file “rbTree.h” #ifndef RED_BLACK_TREE #define RED_BLACK_TREE typedef struct rbTree *rbTree; rbTree newRbTree (); void rbTreeInsert (rbTree t, poly data); void rbTreeDelete (rbTree t, poly data); #endif Red-Black Tree in C // In file “rbTree.c” #include “rbTree.h” struct rbTree { poly data; int color; // 0 for black, 1 for red rbTree left; rbTree right; }; // functions left to you Rank We want to add a “rank” field (property) to the red-black tree: to maintain the tree vertex’s order statistics may after the red-black tree and its operations have been implemented after the fact How to implement this? Red-Black Tree with Rank // In file “rbTree.h” #ifndef RED_BLACK_TREE #define RED_BLACK_TREE typedef struct rbTree *rbTree; rbTree newRbTree (); void rbTreeInsert (rbTree t, poly data); void rbTreeDelete (rbTree t, poly data); void rbTreeInsertRank(rbTree t, poly data, key k); void rbTreeDeleteRank(rbTree t, poly data, key k); int rbTreeRank (rbTree t, poly data, key k); #endif Red-Black Tree in C // In file “rbTree.c” #include “plist.h” #include “rbTree.h” struct rbTree { poly data; int color; // 0 for black, 1 for red plist plist; rbTree left; rbTree right; }; // functions left to you Client Code // In file “main.c” #include “key.h” #include “rbTree.h” int main () { rbTree t1 = newRbTree (); rbTreeInsert (t1, newNat (9)); …; key rank = newKey (); rbTree t2 = newRbTree (); rbTreeInsertRank (t2, newNat (88), rank); …; } Red-Black Tree in Java class RbTree<X> { X data; int color; RbTree<X> left; RbTree<X> right; // constructors and methods omitted void insert (X data){…} void delete (X data){…} … } Red-Black Tree with Rank // Is Inheritance good for this purpose? class RbTreeRank<X> extends RbTree<X> { int size; // constructors and methods are overwritten void insert (X data){…} void delete (X data){…} … } // Not so great! Red-Black Tree with Rank class RbTree<X> { X data; int color; Plist plist; RbTree<X> left; RbTree<X> right; // constructors and methods are overrided void insert (X data){…} void delete (X data){…} void insert (X data, key k); void delete (X data, key k); … } Comparison What’s the representations difference? What’s the efficiency difference? What’s the space efficiency difference? What are the overall wins and hurts of various methods?