I have to create and describe an algorithm for my university course that gets a BST tree T and creates new BST tree T' that satifies properties (and is as fast as possible):
1) T' has the same exact key values as T
2) T' is a Red-Black tree
So far I've had only one idea: randomize 0 or 1. In case of 0, get the max key node from left subtree of T and insert it into T', otherwise get the min key node from right subtree of T and insert it into T'. This is to ensure that Red-Black tree is at least somewhat balanced. The insertion would be any standard RB insertion.
Complexity of getting min/max is O(h), and since this needs to be repeated for each of the nodes in T, this would get quite high. I could also keep a pointer at the max node of left subtree and min node of the right subtree, which would solve the problem of traversing the whole height of the tree every time.
What do you think about this solution? I'm pretty sure it can be done better. Sorry if there is an obvious better solution, but I couldn't find answer to this on the internet, also it's only my 2nd semester at the university and I don't have much experience with programming.
Unless you have some other constraints or information, the fastest way is to forget about the shape of the original BST.
Just put the keys in an ordered list, and build a complete binary tree from it, all in O(N) time.
Then, if there's a partially filled leaf level, then color those nodes red. The rest are black.
Related
If we some how transform a Binary Search Tree into a form where no node other than root may have both right and left child and the nodes the right sub-tree of the root may only have right child, and vice versa, such a configuration of BST is inherently sorted with its root being approximately in the middle (in case of nearly complete BST’s). To to this we need to do reverse rotations. Unlike AVL and red black trees, where roatations are done to make the tree balanced, we would do reversed rotations.
I would like to explain the pseudo code and logical implementation of the algorithm through the following images. The algorithm is to first sort the left subtree with respect to the root and then the right subtree. These two subparts will be opposite to each other, that is, left would interchange with right. For simplicity I have taken a BST with right subtree, with respect to root, sorted.
To improve the complexity as compared to tree sort we can augment the above algorithm. We can add a flag to each node where 0 stands for a normal node while 1 is when the node has non null right child, in the original unsorted BST. The nodes with flag 1 have an entry in a hash table with key being their pointers and the values being the right most node. For example node 23's pointer would map to 30.5's pointer. Then we would not have to traverse all the nodes in between for the iteration. If we have 23's pointer and 30.5's pointer we can do the required operation in O(1). This will bring down time complexity , as compared to tree sort.
Please review the algorithm and give suggestion if this algorithm is usefull.
I am having trouble with these questions:
A binary tree with N nodes is at least how deep?
How deep is it at most?
Would the maximum depth just be N?
There are two extremes that you need to consider.
Every node has just a left(or right) child, but not right child. In which case your binary search tree is merely a linkedlist in practice.
Every level in your tree is full, maybe except the last level. This type of trees are called complete.
Third type of tree that I know may not be relevant to your question. But it is called full tree and every node is either a leaf or has n number of childs for an n-ary tree.
So to answer your question. Max depth is N. And at least it has log(N) levels, when it is a complete tree.
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!
I need to write function, which receives some key x and split 2-3 tree into 2 2-3 trees. In first tree there are all nodes which are bigger than x, and in second which are less. I need to make it with complexity O(logn). thanks in advance for any idea.
edited
I thought about finding key x in the tree. And after split its two sub-trees(bigger or lesser if they exist) into 2 trees, and after begin to go up and every time to check sub-trees which I've not checked yet and to join to one of the trees. My problem is that all leaves must be at the same level.
If you move from the root to your key and split each node so one points at the nodes larger than the key and the other at the rest and then make the larger node be a part of your larger tree, say by having the leftmost node at one level higher point at it, (don't fix the tree yet, do it at the end) until you reach the key you will get your trees. Then you just need to fix both trees on the path you used (note that the same path exists on both trees).
Assuming you have covered 2-3-4 trees in the lecture already, here is a hint: see whether you can apply the same insertion algorithm for 2-3 trees also. In particular, make insertions always start in the leaf, and then restructure the tree appropriately. When done, determine the complexity of the algorithm you got.
I want to sum all the values in the leaves of a BST. Apparently, I can't get to the leaves without traversing the whole tree. Is this true? Can I get to the leaves without taking O(N) time?
You realize that the leaves themselves will be at least 1/2 of O(n) anyway?
There is no way to get the leaves of a tree without traversing the whole tree (especially if you want every single leaf), which will unfortunately operate in O(n) time. Are you sure that a tree is the best way to store your data if you want to access all of these leaves? There are other data structures which will allow more efficient access to your data.
To access all leaf nodes of a BST, you will have to traverse all the nodes of BST and that would be of order O(n).
One alternative is to use B+ tree where you can traverse to a leaf node in O(log n) time and after that all leaf nodes can be accessed sequentially to compute the sum. So, in your case it would be O(log n + k), where k is the number of leaf nodes and n is the total number of nodes in the B+ tree.
cheers
You will either have to traverse the tree searching for nodes without children, or modify the structure you are using to represent the tree to include a list of the leaf nodes. This will also necessitate modifying your insert and delete methods to maintain the list (for instance, if you remove the last child from a node, it becomes a leaf node). Unless the tree is very large, it's probably nice enough to just go ahead and traverse the tree.