Is it always possible to turn one BST into another using at most O(n) tree rotations? - algorithm

This earlier question asks whether it's always possible to turn one BST for a set of values into another BST for the same set of values purely using tree rotations (the answer is yes). However, is it always possible to do this using at most O(n) total tree rotations?

Yes, it is always possible to turn one BST into another using at most O(n) tree rotations. This answer follows the same general approach as the other answer by picking some canonical tree shape T* and bounding the number of rotations needed to turn an arbitrary tree into our canonical tree. Then you can turn an arbitrary tree T₁ into another tree T₂ by transforming T₁ into T* and then transforming T* into T₂.
As suggested in comments, you can choose your canonical tree to be a degenerate linked list. For trees of n nodes, this upper bounds the number of rotations needed at 2n−2.
In the paper Rotation Distance, Triangulation, and Hyperbolic Geometry, Daniel Sleator, Robert Tarjan, and William Thurston proved that the rotation distance between any two binary trees of n nodes is at most 2n−6 (better than the bound we get when transforming into a linked list).
At a high level, they did this by introducing a way to represent any binary tree as a polygon triangulation, where a tree rotation has a corresponding triangulation operation. Then, instead of reasoning about binary trees in their usual representation, the paper picks a canonical triangulation and shows how to transform an arbitrary triangulation into their desired one.
The canonical triangulation they chose is one where all diagonals emanate from a single vertex in a fan-like shape, which ends up corresponding to a somewhat unintuitive binary tree shape (a generalization of linked lists that also includes diamond shaped trees consisting of a root, a left child whose right child is a linked list, and a right child whose left child is a linked list).
It's a very cool technique that illustrates the power of isometries in data structures, showing how changing our representation can give us a new way of approaching a problem. Some friends and I recently put together a writeup walking through Sleator, Tarjan, and Thurston's proof if you would like to explore this in more detail.

Yes, this is always possible. I fear that the best I can do right now is give you a silly algorithm that proves it's possible, though I suspect that there must be a much better way to do this.
The Day-Stout-Warren algorithm is an algorithm that, starting with any BST, uses tree rotations to convert it to a perfectly balanced BST. It runs in time O(n) and does O(n) total rotations.
So suppose that you want to turn one tree T1 into another tree T2 using tree rotations. Run Day-Stout-Warren on both trees to convert them to the same balanced tree T*, and record the rotations that you needed to make in both cases. Then you can turn T1 into T2 by first running all the rotations needed to perfectly balanced T1, then running the reverse of the rotations needed to turn T2 into a balanced tree. This turns T1 into T* and then turns T* into T2. Since the Day-Stout-Warren algorithms makes only O(n) total rotations, this too makes only O(n) total rotations.
I feel like there has to be a better way to do this, but I'm not sure off the top of my head how to achieve this. If I think of anything, I'll let you know!

Related

Graph represented as adjacency list, as binary tree, is it possible?

apologies first, english is not my first language.
So here's my understanding on graph that's represented as adjancey list: It's usually used for sparse graph, which is the case for most of graphs, and it uses V (number of vertex) lists. so, V head pointers + 2e (# of edges) nodes for undirected graph. Therefore, space complexity = O(E+V)
Since any node can have upto V-1 edges (excluding itself) it has time complexity of O(V) to check a node's adjacency.
As to check all the edges, it takes O(2e + V) so O(v + e)
Now, since it's mostly used for sparse graph, it's rarely O(v) to check adjacency, but simply the number of edges a given vertex has (which is O(V) at worst since V-1 is the possible maximum)
What I'm wondering is, is it possible to make the list (the edge nodes) binary tree? So to find out whether node A is adjacent to node B, time complexity would be O(logn) and not linear O(n).
If it is possible, is it actually done quite often? Also, what is that kind of data structure called? I've been googling if such combinations are possible but couldn't find anything. I would be very grateful if anyone could explain this to me in detail as i'm new to data structure. Thank you.
Edit: I know binary search can be performed on arrays. I'm talking about linked list representation, I thought I made it obvious when I said heads to the lists but wow
There's no reason the adjacency list for each vertex couldn't be stored as a binary tree, but there are tradoffs.
As you say, this adjacency list representation is often used for sparse graphs. Often, "sparse graph" means that a particular vertex is adjacent to few others. So your "adjacency list" for a particular vertex would be very small. Whereas it's true that binary search is O(log n) and sequential search is O(n), when n is very small sequential search is faster. I've seen cases where sequential search beats binary search when n is smaller than 16. It depends on the implementation, of course, but don't count on binary search being faster for small lists.
Another thing to think about is memory. Linked list overhead is one pointer per node. Unless, of course, you're using a doubly linked list. Binary tree overhead is two pointers per node. Perhaps not a big deal, but if you're trying to represent a very large graph, that extra pointer will become important.
If the graph will be updated frequently at run time, you have to take that into account, too. Adding a new edge to a linked list of edges is an O(1) operation. But adding an edge to a binary tree will require O(log n). And you want to make sure you keep that tree balanced. An unbalanced tree starts to act like a linked list.
So, yes, you could make your adjacency lists binary trees. You have to decide whether it's worth the extra effort, based on your application's speed requirements and the nature of your data.

Keeping avl tree balanced without rotations

B Tree is self balancing tree like AVL tree. HERE we can see how left and right rotations are used to keep AVL tree balanced.
And HERE is a link which explains insertion in B tree. This insertion technique does not involve any rotations, if I am not wrong, to keep tree balanced. And therefore it looks simpler.
Question: Is there any similar (or any other technique without using rotations) to keep avl tree balanced ?
The answer is... yes and no.
B-trees don't need to perform rotations because they have some slack with how many different keys they can pack into a node. As you add more and more keys into a B-tree, you can avoid the tree becoming lopsided by absorbing those keys into the nodes themselves.
Binary trees don't have this luxury. If you insert a key into a binary tree, it will increase the height of some branch in that tree by 1 in all cases because that key needs to go into its own node. Rotations combat the overall growth of the tree by ensuring that if certain branches grow too much, that height is shuffled into the rest of the tree.
Most balanced BSTs have some sort of rebalancing strategy that involves rotations, but not all do. One notable example of a strategy that doesn't directly involve rotations is the scapegoat tree, which rebalances by tearing huge subtrees out of the master tree, optimally rebuilding them, then gluing the subtree back into the main tree. This approach doesn't technically involve any rotations and is a pretty clean way to implement a balanced tree.
That said - the most space-efficient implementations of scapegoat trees do indeed use rotations to convert an imbalanced tree into a perfectly balanced one. You don't have to use rotations to do this, though if space is short it's probably the best way to do so.
Hope this helps!
Rotations can be made simple (if you need only simplicity).
If the insertion traffic is left, the balance -1 is the red-light.
If the insertion traffic is right, the balance 1 is the red-light.
This is a (simplified) coarse-graining (2-adic rounding) of the normalized fundamental AVL balance:
{left,even,right} ~ {low,even,high} ~ {green,green,red}
Walk the insertion route and rotate every red-light (before the insertion). If the next light is green, you can just rotate the red-light 1 or 2 times. You may have to re-balance the next subtrees before each rotation, because inner subtrees are invariant. This is simple, but it takes a very long time. You have to move down the green-light before each rotation. You can always move down the green-light to the root, and you can rotate the tree-top to generate a new green-light.
The red-light rotations naturally move down the green-light.
At this point, you have only the green-lights for the insertion.
The cost structure of this naive method is topologically simplified as
df(h)/dh=∫f(h)dh
such as sin(h),sinh(h),etc.

Splay tree rotation algorithm: Why use zig-zig and zig-zag instead of simpler rotations?

I don't quite understand why the rotation in the splay tree data structure is taking into account not only the parent of the rating node, but also the grandparent (zig-zag and zig-zig operation). Why would the following not work:
as we insert, for instance, a new node to the tree, we check whether we insert into the left or right subtree. If we insert into the left, we rotate the result RIGHT, and vice versa for right subtree. Recursively it would be sth like this
Tree insert(Tree root, Key k){
if(k < root.key){
root.setLeft(insert(root.getLeft(), key);
return rotateRight(root);
}
//vice versa for right subtree
}
That should avoid the whole "splay" procedure, don't you think?
The algorithm you're proposing on the tree is called the "move-to-root" heuristic and is discussed on page four of Sleator and Tarjan's original paper on splay trees. They cite an older paper by Allen and Munro where it is shown that if you try to use move-to-root as a means for reshaping trees, it is possible for the amortized cost of each lookup to be O(n), which is quite slow. Splaying is a very carefully designed algorithm for reshaping the tree, and it guarantees amortized O(log n) lookups no matter what sequence of accesses is performed.
Intuitively, move-to-root is not a very good way to reshape the tree because it moves down all the nodes on the path from the node to the root while trying to make the accessed node easier to reach in the future. As a result, the overall tree can get worse when doing this version of tree reorganizing. On the other hand, the splay method tends to decrease the height of the splayed node and all of the nodes on its access path, which means that as a whole the tree tends to get better during a splay.
Hope this helps!

Fortunes Algorithm - Beach Line Data Structure

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.

How i can merge two binary trees

I have two binary trees and I want to merge them.
My first question is that whether we can merge two binary trees and if yes how efficiently I can perform the merge operations and what are the various ways i can perform the merging operations. ..?
1) Flatten both the trees in to sorted lists.
2) Merge the lists from what you got in 1)
3) Construct the tree out of what you got in 2)
This algorithm might help you.
Not considering efficiency this answer may work Algorithm of combining two binary trees? . If sorted or balanced, discussion on efficiency in How to merge two BST's efficiently? and Concatenating/Merging/Joining two AVL trees
Create a new node and point one tail at the head of one of the trees and point the other tail at the head of the other tree. Perhaps you need to clarify your question to be more specific. What relationships are you trying to preserve?
A tree is also a graph, so output the edge vertex-pairs (u,v) for each tree, and then union these edge sets, and output the resulting graph.
The issue arises with how to map vertices in the one tree to vertices in the other (e.g. we have edge pair (5,9) in tree 1 and edge pair (5,6) in tree 2, do these 5s correspond to the same vertex ? ).
Coming up with a numbering of vertices (perhaps that assigns numbers to each vertex in an incomplete binary tree, as if it were a complete binary tree, so in other words assigns the vertices in any partial binary tree to slots of a hypothetical complete binary tree of which that tree is a subtree), that somehow provides an desirable equivalence is something that works.

Resources