How do you display a binary search tree? - binary-tree

I'm being asked to display a binary search tree in sorted order. The nodes of the tree contain strings.
I'm not exactly sure what the best way is to attack this problem. Should I be traversing the tree and displaying as I go? Should I flatten the tree into an array and then use a sorting algorithm before I display?
I'm not looking for the actual code, just a guide where to go next.

Check out your options for Tree Traversal, it's easier than you might think. Good luck :)

Is this a binary search tree (BST)? A "just" binary tree (not search) has no properties that would in any way help you (indeed, there may not be any order defined among the payloads!), but for a BST the situation is totally different (indeed the first wikipedia page I pointed to gives concise pseudocode (well, OK, Python;-) for in-order traversal of a BST -- not for just any binary tree of course.
So, did you omit the absolutely-crucial word search between "binary" and "tree" in your question and tag?

Binary Search Tree is a just a tree that you can print as a classic ways (preorder, inorder, preorder)
for example :
print(node){
if(node != null){
printOut(root.value);
print(node.left);
print(node.right);
}
}

Related

When can we use Simple Binary Tree over Binary Search Tree?

Lots of tutorials focus on implementation of Binary Search Tree and it is easier for search operations. Are there applications or circumstances where implementing a Simple Binary Tree is better than BST? Or is it just taught as an introductory concept for trees?
You use a binary tree (rather than a binary search tree) when you have a structure that requires a parent and up to two children. For example, consider a tree to represent mathematical expressions. The expression (a+b)*c becomes:
*
/ \
+ c
/ \
a b
The Paring heap is a data structure that is logically a general tree (i.e. no restriction on the number of children a node can have), but it is often implemented using a left-child right-sibling binary tree. The LCRS binary tree is often more efficient and easier to work with than a general tree.
The binary heap also is a binary tree, but not a binary search tree.
The old guessing game where the player answers a bunch of yes/no questions in order to arrive at an answer, is another example of a binary tree. In the tree below, the left child is the "No" answer, and the right child is "Yes" answer
Is it an animal?
/ \
Is it a plant? Is is a mammal?
/ \
A reptile? A dog?
You can imagine an arbitrarily deep tree with questions at each level.
Those are just a few examples. I've found binary trees useful in lots of different situations.

Mirror a binary tree in constant time

This is not a homework question. I heard that it is possible to mirror a binary tree i.e. flip it, in constant time. Is this really the case?
Sure, depending on your data structure, you would just do the equivalent of: instead of traversing down the left node and then the right node, you would traverse down the right node, and then the left node. This could be a parameter passed into the recursive function that traverses the tree (i.e. in C/C++, a bool bDoLeftFirst, and an if-statement that uses that parameter to decide which order to traverse the child nodes in).
Did you mean "invert binary tree", the problem which Max Howell could not solve and thus rejected by Google?
https://leetcode.com/problems/invert-binary-tree/
You can find solutions in the "discuss" section.

Threaded Binary Search Trees Advantage

An explanation about Threaded Binary Search Trees (skip it if you know them):
We know that in a binary search tree with n nodes, there are n+1 left and right pointers that contain null. In order to use that memory that contain null, we change the binary tree as follows -
for every node z in the tree:
if left[z] = NULL, we put in left[z] the value of tree-predecessor(z) (i.e, a pointer to the node which contains the predecessor key),
if right[z] = NULL, we put in right[z] the value of tree-successor(z) (again, this is a pointer to the node which contains the successor key).
A tree like that is called a threaded binary search tree, and the new links are called threads.
And my question is:
What is the main advatage of Threaded Binary Search Trees (in comparison to "Regular" binary search trees).
A quick search in the web has told me that it helps to implement in-order traversal iteratively, and not recursively.
Is that the only difference? Is there another way we can use the threads?
Is that so meaningful advantage? and if so, why?
Recursive traversal costs O(n) time too, so..
Thank you very much.
Non-recursive in-order scan is a huge advantage. Imagine that somebody asks you to find the value "5" and the four values that follow it. That's difficult using recursion. But if you have a threaded tree then it's easy: do the recursive in-order search to find the value "5", and then follow the threaded links to get the next four values.
Similarly, what if you want the four values that precede a particular value? That's difficult with a recursive traversal, but trivial if you find the item and then walk the threaded links backwards.
The main advantage of Threaded Binary Search Trees over Regular one is in Traversing nature which is more efficient in case of first one as compared to other one.
Recursively traversing means you don't need to implement it with stack or queue .Each node will have pointer which will give inorder successor and predecessor in more efficient way , while implementing traversing in normal BST need stack which is memory exhaustive (as here programming language have to consider implementation of stack) .

Balancing a ternary search tree

How does one go about 'balancing' a ternary search tree? Most tst implementations don't address balancing, but suggest inserting in an optimal order (which I can't control.)
The article in Dr. Dobbs about Ternary Search Trees says: D.D. Sleator and R.E. Tarjan describe theoretical balancing algorithms for ternary search trees in "Self-Adjusting Binary Search Trees" (Journal of the ACM, July 1985). You can find online versions of this paper with your favorite search engine.
One simple optimization is to make it a red-black tree, which can avoid some worst-case scenarios. TSTs are really just binary trees where the value of a given node is another TST. So, the "middle" child of a node is not really part of the tree that is being balanced at each level, as it cannot move to a different parent anyway.
This ensures that each tier of the trie is traversed in log(R) time, although you could probably do even better by taking into account the size of the subtries at each node. That looks to be a lot more complicated though!
A generalization of the binary search tree is the B-Tree, which works for fanouts anywhere from 2 and up. That's not the only way to do it, but it's a common one.
Roughly the way it works is if an insert or delete would put the tree out of balance, it steals an element or a space from a neighboring node. If even that isn't enough to keep the tree in balance, its height by will be changed to make room.
read this article:
"Self-Adjusting of Ternary Search Tries Using Conditional Rotations and Randomized Heuristics"
by
"Ghada Hany Badr∗ and B. John Oommen †"
it will help you to understanding self-adjusting and balancing TSTs.

Question on Binary Search Trees

I was thinking of implementing a binary search trees. I have implemented some very basic operations such as search, insert, delete.
Please share your experiences as to what all other operations i could perform on binary search trees, and some real time operations(basic) that is needed every time for any given situation.. I hope my question was clear..
Thanks.
Try a traversal operation (e.g., return the elements in the tree as a List, in order) and make sure that the tree remains balanced when elements are inserted/deleted.
You may want to look at the different ways of returning the tree:
Depth-first (going all the way down a branch and back up, repeat)
In-order (going around the tree)
Level-order (each level as drawn in a diagram)
Returning as a flat array.
And if you're feeling particularly adventurous, take an array and import it in as a tree. There is a specific format for this that goes something like (1(2(3)),(5) - that example isn't balanced but you get the idea, and it's on Wikipedia.
You might also want to implement a rotation operation. A rotation changes the structure without change the order of the elements. This is usually used to balance the tree (to make sure the leaves are all close to the same depth) and can also be used to change the root to a given element if you know it will be showing up in the search more often.
My ASCII art is not great, but a rotation can turn this tree:
f
d g
b e
a c
into this tree:
d
b f
a c e g
The second tree being balanced will make searches for f and g slower, and searches for d,a,b,c faster with e staying the same.
If this is homework, Good luck!
If this is curiousity, have fun!
If you want to implement this in production code without even knowing the basic operations, Don't do it!
http://www.boost.org/doc/libs/1_38_0/boost/graph/detail/array_binary_tree.hpp
At the very least, a binary search tree should have an insert, delete, and search operation. Any other operations will depend on what you intend to do with your tree, although some generic suggestions are: return parent of a given node, find left and right child of a given node, return the root node, preorder, inorder, and postorder traversals, as well as a breadth-first traversal.
If you really just want a list of stuff that might be useful or fun to implement...
Reverse the order of everything in the tree. This is O(N) I think?
Subtree, elements between x and y as a binary search tree themselves -- should be O(log N) I think?
Minimum, maximum? Yeah, trivial but I'm out of ideas!
I think I've seen somewhere "map" operation. When you change all elements of tree with monotonic function. I.e. function with property to always ascend ( f(x+dx) >= f(x) ) or always descend ( f(x+dx) <= f(x) ). In one case you'll need to apply that function to each node in other you'll need also to mirror tree (swap "left" and "right" nodes) because order of resulted values will be reversed.

Resources