Download Extensible DS

Document related concepts
no text concepts found
Transcript
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?