Looking
into representations of graphs, the representation with
objects&pointers
is favorable to the adjacency-list representation and adjacency-matrix representation
when the graph is a tree of type
n-ary, binary (ordinary binary, balanced-- red-black, AVL, etc) trie, b-tree, ... , and obviously not a heap.
This is because:
1.) in a tree structure, the edges have distinct meanings-- "left-child",
"right-child", "parent", "i-th child" in b-trees,
the link value in tries/radix trees, etc.
Tree operations require the traversal of a specific link-- based on the link types
(left-, right-, .. i-th-child, etc).
The use of pointers can easily allow to distinguish the link types.
Adjacency list representation would require an extra field on the
link-node to tell what kind of a link it is.
Matrix representation would require coded matrix entries to tell what kind of a link it is.
2.) Tree operations often require moving around the subtrees of a node.
This can easily be done,
in constant time, by changing the pointer values.
In an adjacency list and matrix representations,
this operation would take searching for the link-to-be altered
in the edge-list of the nodes and is linear in the number of edges or the graph degree-- no longer in O(1).
The object&pointer representation of a tree can be backed by array structures:
So, each vertex is
still represented by an object. This object has a pointer to each child and one
to the parent (whichever the way the tree being implemented calls for).
But this time, the objects are array entries, and the pointer values are array indices. This is a mix of adjacency-list and objects&pointers representations of graphs
and is powerful.
My Q is: What other general cases are there in the representations of graphs
where the representation with objects&pointers is preferable to the adjacency-list
representation and to the the adjacency-matrix
representation?
I'm looking for references to this.
Thanks in advance.
Related
In their book Computational Geometry (2008), de Berg, et al., describe the data structure underlying their range search algorithm as a balanced BST where "leaves of T store the points of P and the internal nodes of T store splitting values to guide the search."
The Wikipedia page on range trees (link), which cites de Berg, says: "A 1-dimensional range tree on a set of n points is a binary search tree" such that "each node which is not a leaf stores the largest value of its left subtree."
Examples online construct such trees statically, by first sorting the set of points and then recursively pairing up nodes.
Does there exist an algorithm to build a BST of this nature dynamically (i.e., with the ability to insert additional values into the tree)? Where is it described?
It's possible to adapt just about any tree balancing procedure to work with these two examples, just by treating the leaves separately -- make a balanced tree of the internal nodes, and then take care to keep the leaves in order. Each operation, including balancing, will require you to recalculate the "summary statistics" on at most O(log N) nodes. Those are all the nodes that were updated and their ancestors.
This can be a little complicated, though, and doesn't work for the multi-dimensional range tree, because every level is treated differently from the ones above and below, and that makes tree rotations (which most balancing operations require) invalid.
For these kinds of trees, therefore, where different levels are handled differently, it is usually best to just avoid tree rotations by using a low-order B+tree variant like a 2-3 tree. In a tree like this, nodes can be split and merged, but they never have to change height -- you can implement them so that leaves are always leaves and internal nodes are always internal. The height of the tree is only ever changed by adding or removing the root.
Of course, if you use a tree that can have more than 2 children per node, then your search algorithms will need to change, but the changes are typically trivial.
Just been learning about binary trees in school, and two rules of binary trees is that
every node has at most 2 child nodes
there exists linear ordering defined for the children of each node (ordered pair)
Now, all types of binary trees (full, complete, etc.) are binary trees so they must satisfy these 2 conditions.
However, I saw on GeeksForGeeks this example:
How is 'linear ordering', ordered pair, defined here?
It seems that for the sibling nodes in this picture, some left ones are larger than the right one, some right nodes are larger than the left one.
If asked to check if a given tree is a binary tree, how do I make sure of the second property, that the children of each node have to be ordered?
Thanks
This is one of the complicated ways to introduce a binary tree.
two rules of binary trees is that
every node has at most 2 child nodes
there exists linear ordering defined for the children of each node (ordered pair)
Simple ways of introducing binary trees I could think of are "at most two children and no cycles" or "at most two children and unique path between any pair of vertices".
But fine. You bring up the point of linear order. Lets discuss that.
Here
A linear ordering on a finite collection of objects may be described
as follows: each object has exactly one immediate predecessor object
and one immediate successor object with two exceptions: A first object
has no predecessor and a last object has no successor.
If you have learnt about traversal so far, with the above definition, I would take binary tree traversals as linear order - preorder, postorder, inorder, level order. This applies to all types of binary trees (full, complete, etc.) which includes the complete binary tree you posted as an image.
I'm reading about AVL tree and there I redirected to self balancing tree there I read that
In computer science, a self-balancing (or height-balanced) binary
search tree is any node-based binary search tree that automatically
keeps its height (maximal number of levels below the root) small in
the face of arbitrary item insertions and deletions.1
These structures provide efficient implementations for mutable ordered
lists, and can be used for other abstract data structures such as
associative arrays, priority queues and sets.
I'm confused
What is the relation of height to list? array?
how small height tree provide efficient implementations for mutable ordered lists? array? queues?
Let suppose the node of list or index of array are height of list or
array, how it could be small?
Here is a visual on balance
2. Remember that trees offer a unique path to every node. Because AVL trees are binary search trees we "know" which direction to go when given a value, because the tree is sorted. AVL trees (for every node, the heights of the left and right subtrees differ by at most 1) allow for quick searches and insertions, usually log N, because it can rotate and manipulate itself in constant time. We can implement an ordered list, queue, etc. values into a tree structure to leverage its characteristics. The key is the tree remaining balanced (stays horizontal not vertical, which it does by following the binary search tree trait).
Can you elaborate on 1 and 3?
I keep seeing everywhere that there are 3 ways to represent graphs:
Objects and pointers
Adjacency matrix
Adjacency lists
However, I just plain don't understand what these Object and pointer representations are - yet every recruiter, and many blogs cite Steve Yegge's blog that they are indeed a separate representation.
This widely accepted answer to a very similar question seems to suggest that the vertex structures themselves have no internal pointers to other vertices, and instead all edges are represented by edge structures which contain pointers to the adjacent vertices.
How does this representation offer any discernible analytical advantage in any scenario?
From the top of my head, I hope I have the facts correct.
Conceptually, graph tries to represent how a set of nodes (or vertices) are related (connected) to each other (via edges).
However, in actual physical device (memory), we have a continuous array of memory cell.
So, in order to represent the graph, we can choose to use a matrix.
In this case, we use the vertex index as the row and column and the entry has value 1 if the vertices are adjacent to each other, 0 otherwise.
Alternatively, you can also represent a graph by allocating an object to represent the node/vertex which points to a list of all the nodes that are adjacent to it.
The matrix representation gives the advantage when the graph is dense, meaning when most of the nodes/vertices are connected to each other. This is because in such cases, by using the entry of matrix, it saves us from having to allocate an extra pointer (which need a word size memory) for each connection.
For sparse graph, the list approach is better because you don't need to account for the 0 entries when there is no connection between the vertices.
Hope it helps.
For now I have a hard time finding a pro w.r.t typical "graph algorithms". But it sure is possible to represent a graph with objects and pointers and a very natural thing to do if you think of it as a representation of something you just drew on a whiteboard.
Think of a scenario where you want to combine nodes of a graph in a certain order.
Nodes have payloads that contain domain data, the graph structure itself is not a core aspect of your program.
Sure, you can update your lists / matrix for every operation, but given an "objects and pointers" structure, you can do the merging locally. Further, if nodes have payloads, it means that lists/matrix will feature node id's that identify the actual node objects. A combination would mean you update your graph representation, follow the node identifiers and do the actual processing. It may feel more intuitively to work on your actual node objects and simply remove pointerswhen collapsing a neighbor (and delete that node) .
Besides, there are more ways to represent a graph:
E.g. just as triples, like Turle does
Or as offset
representation (offsets per node into an edge array), e.g. this
Boost data structure (disclaimer: I have not tested the linked
implementation myself)
etc
Here a way i have been using to create Graph with this concept :
#include <vector>
class Node
{
public:
Node();
void setLink(Node *n); // *n as argument to pass the address of the node
virtual ~Node(void);
private:
vector<Node*> m_links;
};
And the function responsible for creating the link between vertices is :
void Node::setLink(Node *n)
{
m_links.push_back(n);
}
Objects and pointers representation reduces space complexity to exactly V+E, where V is the number of vertices, E - the number of edges (down from V+2E in Adjacency List or even 2V+2E if you store index->Vertex mapping in a separate hash map), sacrificing time complexity: particular edge lookup will take O(E), which equals O(V^2) in a Dense graph (up from O(V) in Adjacency List). The space saving is achieved by removing duplicated edges that appear in the Adjacency List.
I have to implement Fortunes algorithm for constructing Voronoi diagrams.
Important part of the algorithm is a data structure called "Beach Line Data Structure".
It is a binary balanced tree, similar to AVL, but different in a way that data is stored only on the leafs (there are other differences, but are unimportant for the question).
I am not sure how to implement it. Obviously using AVL "as is" will not work because when balancing AVL tree leaf node can become inner node and vice versa.
I also tried to look at some other known data structures at wikipedia, but none suits the needs.
I have seen some implementations that do this with a linked list, but this is not good because searching linked list is O(n), and it needs to be O(log n) for the algorithm to be efficient.
The leaves indeed store (single) points and the inner nodes of the event structure (the "beach line tree") stores ordered tuples of points whose parabolas/arcs lie next to each other. If the parabola that point Pa forms lies to the left of the parabola formed by Pb (and these two parabola's intersect), the inner node stores the ordered tuple (Pa, Pb).
Obviously using AVL "as is" will not work because when balancing AVL tree leaf node can become inner node and vice versa.
If you're worried about storing different types of objects in the AVL tree, a simple scheme would be to store the leaves as tuples too. So don't store point Pj as a leaf, but store the tuple (Pj, Pj) instead. If Pj as a leaf disappears from the event tree (beach line), and its parent is (Pi, Pj), simply change the parent into (Pj, Pj), and of course its parent will also needs to be changed from (Pj, P?) to (Pi, P?) etc. Just as with a regular AVL tree: you walk up the tree and modify the inner nodes that need to be changed and/or re-balanced.
Note that a good implementation of the algorithm can't be easily written down in a SO answer (at least, not by me!). For a proper explanation of the entire algorithm, including a description of the data structures used by it, see Computational geometry: algorithms and applications by Mark de Berg et al.. Chapter 7 is devoted solely to Voronoi diagrams.