Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Dynamically Extensible Data
Structures
Discrete Mathematics and
Its Applications
Baojian Hua
bjhua@ustc.edu.cn
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?