The following is a high-level description of the design; low-level details appear further below. The graph is implemented via a list of vertices and a list of edges. The nodes of these "global" lists are the vertices and edges of the graph, respectively. In addition to the global lists of vertices and edges, each vertex has a "local" list of its incident edges. Thus, each edge participates in two local lists (one for each endpoint) plus the global list. Each vertex participates in only the global list. Although sequential data structures are used to implement the graph, the graph conceptually consists of unordered sets; no guarantee is made about where in the various lists a given accessor appears.
This design forces most of the methods' time complexities. Insertion and deletion of vertices and edges are constant-time because the various doubly-linked lists can be modified in constant time. Adjacency queries are typically O(degrees of vertices involved). Iterations take time linear in the number of things iterated over.
The remainder of this description is about low-level details of the design, and efficiency tradeoffs of alternate designs.
The global list of edges exists to avoid having the duplicates in edges() that would result from asking all vertices for their incident edges (each edge would appear twice). For most other purposes, the only global list required would be the vertex list. An alternate design would get rid of the global edge list and would do a traversal to get edges(). This would save space at the cost of increasing the complexity of edges() from O(E) to O(V+E).
Both global lists are implemented with JDSL NodeSequences. In contrast, the local incidence lists at each vertex are implemented "by hand," with links in the ILEdges, for space efficiency. Internal methods that refer to those links also take a vertex, so the edge knows which set of links is being referred to (the set for one endpoint or the set for the other endpoint). Each local list includes a dummy edge to handle special cases (empty list, iterating till end of list, inserting at beginning of list).
To avoid the space overhead of having the global lists' positions point to vertex/edge objects, which would need to point back to the positions, the positions *are* the vertices/edges. This is accomplished by inheriting from the position implementation of the NodeSequence (called FNSNode) and using the posInsert* methods to put objects of the subclass into the global lists.
Research issues. The following are changes to the design that could be made if experiments indicated they were worthwhile:
|
|
|
|