Flatten Binary Tree --> Singly Linked List (Ruby) - ruby

I'm working on a recursive algorithm to flatten a binary tree into a singly linked list. Problem statement:
Given a binary tree, flatten it to a linked list in-place.
For example,
Given
1
/ \
2 5
/ \ \
3 4 6
The flattened tree should look like:
1
\
2
\
3
\
4
\
5
\
6
I wrote the following recursive code that simply doesn't work (returns wrong answer), but I can't understand conceptually why not. Starting at the root, we flatten root.left and root.right. If root.left exists, then root.next (or in this case, root.right) will point to the flattened left list. Then, the left list points to the beginning of the right list. This continues recursively down the tree.
Is something wrong with this conceptually? I tried modeling it after a preorder traversal since essentially root is visited, then left, then right.
def flatten(root)
return root if root.nil?
left_list = flatten(root.left)
right_list = flatten(root.right)
root.left = nil
root.right = (left_list.nil? ? right_list : left_list)
find_tail(left_list).right = right_list unless left_list.nil?
end
def find_tail(node)
return nil if node.nil?
until node.right.nil?
node = node.right
end
node
end

Your flatten does not return what it should. It matters as you call it recursively. Change it to
...
find_tail(left_list).right = right_list unless left_list.nil?
root # <-- add this line
end

Related

breadth of a binary tree

How do we determine breadth a of binary tree.
A simple bin tree
O
/ \
O O
\
O
\
O
\
O
Breadth of above tree is 4
You could use a recursive function that returns two values for a given node: the extent of the subtree at that node towards the left (a negative number or zero), and the extent to the right (zero or positive). So for the example tree given in the question it would return -1, and 3.
To find these extends is easy when you know the extents of the left child and of the right child. And that is where the recursion kicks in, which in fact represents a depth-first traversal.
Here is how that function would look in Python:
def extents(tree):
if not tree:
# If a tree with just one node has extents 0 and 0, then "nothing" should
# have a negative extent to the right and a positive on the left,
# representing a negative breadth
return 1, -1
leftleft, leftright = extents(tree.left)
rightleft, rightright = extents(tree.right)
return min(leftleft-1, rightleft+1), max(leftright-1, rightright+1)
The breadth is simply the difference between the two extents returned by the above function, plus 1 (to count for the root node):
def breadth(tree):
leftextent, rightextent = extents(tree)
return rightextent-leftextent+1
The complete Python code with the example tree, having 6 nodes, as input:
from collections import namedtuple
Node = namedtuple('Node', ['left', 'right'])
def extents(tree):
if not tree:
return 1, -1
leftleft, leftright = extents(tree.left)
rightleft, rightright = extents(tree.right)
return min(leftleft-1, rightleft+1), max(leftright-1, rightright+1)
def breadth(tree):
left, right = extents(tree)
return right-left+1
# example tree as given in question
tree = Node(
Node(
None,
Node(None, Node(None, Node(None, None)))
),
Node(None, None)
)
print(breadth(tree)) # outputs 4

Find Leaves of Binary Tree

Working on following problem:
Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.
Example:
Given binary tree
1
/ \
2 3
/ \
4 5
Returns [4, 5, 3], [2], [1].
Explanation:
1. Removing the leaves [4, 5, 3] would result in this tree:
1
/
2
2. Now removing the leaf [2] would result in this tree:
1
3. Now removing the leaf [1] would result in the empty tree:
[]
Returns [4, 5, 3], [2], [1].
My idea was a simple recursive algorithm shown below. The idea is to find the leaves of the left subtree and the right subtree, and weave them such that the depths are in the right subarray. I've tested the 'weave' method pretty thoroughly, and I think it's fine. My concern is with my recursive implementation-- I'm getting an answer way off from the correct one, and not sure why.
Below is my code with sample input/output:
def find_leaves(root)
return [] if root.nil?
#create leaf_arr of root.left and root.right
#weave them in order.
#add the root
left_arr = find_leaves(root.left)
right_arr = find_leaves(root.right)
weave(left_arr, right_arr) << [root]
end
def weave(arr1, arr2) #these are 2d arrs
i = 0
until i == arr1.length || i == arr2.length #potential nil/empty case here
arr1[i] += arr2[i]
i += 1
end
if i < arr2.length
#either arr 1 or arr2 isn't finished. if arr1 isn't finished, we're done. if arr2 isnt finished, do the below:
until i == arr2.length
arr1 << arr2[i]
i += 1
end
end
arr1
end
Sample input/output/correct answer:
Run Code Result: ×
input: [1,2,3,4,5]
Your answer: [[[4],[5],[3]],[[2,4,5]],[[1,2,3,4,5]]]
Expected answer: [[4,5,3],[2],[1]]
I've printed the output for the left_arr and right_arr variables and they look fine, and I've stress-tested my weave algorithm. Am I off conceptually here?
I can't comment so I will do it like this. (do remember that i dont know ruby)
I think something goes already wrong in how the double arrays (root.left and root.right) are defined. How are they defined? how is root defined?
But the following eplains the repeat of the whole array.
weave(left_arr, right_arr) << [root]
This should be someting in the line of this.
weave(left_arr, right_arr) << [root.root]
Otherwise you are appending the whole root array wich is [1,2,3,4,5].
So this explains the adding of last part. [[[4],[5],[3]],[[2,4,5]],[[1,2,3,4,5]]].
My suggestion in finding the error in weave would be to print arr1 and arr2 at every stage....
Could you show that..
In your code you are using pure depth first search algorithm DFS and with that algorithm I think that you can hardly achieve your goal with array joggling you are doing in weave function. Because your tree will be processed in this order 4 , 5 , 2 , 3 , 1.
One solution will be to do it with iteration (pseudo code):
function doJob(root) begin
leaves = findLeaves(root)
while leaves.size > 0 do begin
for each leaf in leaves delete(leaf)
leaves = findLeaves(root)
end
delete(root)
end
function findLeaves(node) begin
if node = nil then begin
return []
end
else begin
leftLeaves = findLeaves(node.left)
rightLeaves = fingLeaves(node.right)
leaves = leftLeaves + rightLeaves
if leaves.size == 0 then begin
leaves.add(node)
end
return leaves
end
end
Since this still sits open and seems to fair highly when I google search your title. I'll show a pretty expressive solution:
def find_leaves(root)
return [] if root.nil?
return [[root.val]] if root.left.nil? && root.right.nil?
todo = [root]
leaves = []
until todo.empty?
top = todo.shift
%w[left right].each do |path|
leaf = top.send(path)
next if leaf.nil?
if leaf.left.nil? && leaf.right.nil?
leaves << leaf.val
top.instance_variable_set("##{path}", nil)
else
todo << leaf
end
end
end
[leaves].concat(find_leaves(root))
end
A more refactored version:
def find_leaves(root)
leaves = []
search = lambda do |branch|
return -1 unless branch
i = 1 + [search[branch.left], search[branch.right]].max
(leaves[i] ||= []) << branch.val
i
end
search[root]
leaves
end
They're both about the same speed, and really the first one is easier to read and understand.

Depth First Search Efficiency

I have implemented a DFS method which takes in a search value and a Binary Search Tree as arguments. The method then searches the tree for the given value, returning it when found.
When I call the method, there appears to be a duplicate node visit which may be affecting the efficiency. Is this visit in fact a duplication or just a reflection of the nature of DFS?
For instance, if my binary tree looks like the one below and I'm looking for the the value 3, the search is popping the 5 node off the stack, then the 2, then the 1, then retrieving the 2 node from the stack again before finding the 3. Is this stack retrieval of the 2 duplicative? Is it a proper DFS?
5
/ \
/ \
2 7
/ \ / \
1 3 6 8
\ \
4 9
Binary Tree
class Node
attr_accessor :value, :left, :right
def initialize(value)
#value = value
end
end
def build_tree(array, *indices)
array.sort.uniq!
mid = (array.length-1)/2
first_element = indices[0]
last_element = indices[1]
if !first_element.nil? && first_element >last_element
return nil
end
root = Node.new(array[mid])
root.left = build_tree(array[0..mid-1], 0, mid-1)
root.right = build_tree(array[mid+1..-1], mid+1, array.length-1)
return root
end
Depth First Search Method
def depth_first_search(search_value, tree)
stack = [tree]
visited = [tree]
while !stack.empty?
current = stack.last
visited << current
puts current
p current
if current.value == search_value
puts current
exit
elsif !current.left.nil? && !visited.include?(current.left)
if current.left.value == search_value
puts current.left
exit
else
visited << current.left
stack << current.left
end
elsif !current.right.nil? && !visited.include?(current.right)
if current.right.value == search_value
puts current.right
exit
else
visited << current.right
stack << current.right
end
else
stack.pop
end
end
puts "nil"
end
Method Call
binary_tree = build_tree([1,2,3,4,5,6,7,8,9])
depth_first_search(3, binary_tree)
Now, since it is DFS, it works that way. DFS in a binary-tree works exactly like pre-order traversal of the tree. So, for the example tree in the figure, DFS would be visiting like:
5-2-1-(2)-3-4-(3)-(2)-(5)-7-6-(7)-8-9
Here, the values in brackets is the "second visit" that you are calling, but, it does not actually visit those nodes. So, it is alright.
Also, I'd recommend using a binary search if the input tree is BST (not DFS).

Pseudocode to compare two trees

This is a problem I've encountered a few times, and haven't been convinced that I've used the most efficient logic.
As an example, presume I have two trees: one is a folder structure, the other is an in-memory 'model' of that folder structure. I wish to compare the two trees, and produce a list of nodes that are present in one tree and not the other - and vice versa.
Is there an accepted algorithm to handle this?
Seems like you just want to do a pre-order traversal, essentially. Where "visiting" a node means checking for children that are in one version but not the other.
More precisely: start at the root. At each node, get a set of items in each of the two versions of the node. The symmetric difference of the two sets contains the items in one but not the other. Print/output those. The intersection contains the items that are common to both. For each item in the intersection (I assume you aren't going to look further into the items that are missing from one tree), call "visit" recursively on that node to check its contents. It's a O(n) operation, with a little recursion overhead.
public boolean compareTrees(TreeNode root1, TreeNode root2) {
if ((root1 == null && root2 != null) ||
(root1 != null && root2 == null)) {
return false;
}
if (root1 == null && root2 == null) {
return true;
}
if (root1.data != root2.data) {
return false;
}
return compareTrees(root1.left, root2.left) &&
compareTrees(root1.right, root2.right);
}
If you use a sort tree, like an AVL tree, you can also traverse your tree efficiently in-order. That will return your paths in sorted order from "low" to "high".
Then you can sort your directory array (e.g. Using quicksort) using the same compare method as you use in your tree algorithm.
Then start comparing the two side by side, advancing to the next item by traversing your tree in-order and checking the next item in your sorted directory array.
This should be more efficient in practice, but only benchmarking can tell.
A simple example code in python.
class Node(object):
def __init__(self, val):
self.val = val
self.child = {}
def get_left(self):
# if left is not in the child dictionary that means the element does not have a left child
if 'left' in self.child:
return self.child['left']
else:
return None
def get_right(self):
# if right is not in the child dictionary that means the element does not have a right child
if 'right' in self.child:
return self.child['right']
else:
return None
def traverse_tree(a):
if a is not None:
print 'current_node : %s' % a.val
if 'left' in a.child:
traverse_tree(a.child['left'])
if 'right' in a.child:
traverse_tree(a.child['right'])
def compare_tree(a, b):
if (a is not None and b is None) or (a is None and b is not None):
return 0
elif a is not None and b is not None:
print a.val, b.val
# print 'currently comparing a : %s, b : %s, left : %s, %s , right : %s, %s' % (a.val, b.val, a.child['left'].val, b.child['left'].val, a.child['right'].val, b.child['right'].val)
if a.val==b.val and compare_tree(a.get_left(), b.get_left()) and compare_tree(a.get_right(), b.get_right()):
return 1
else:
return 0
else:
return 1
# Example
a = Node(1)
b = Node(0)
a.child['left'] = Node(2)
a.child['right'] = Node(3)
a.child['left'].child['left'] = Node(4)
a.child['left'].child['right'] = Node(5)
a.child['right'].child['left'] = Node(6)
a.child['right'].child['right'] = Node(7)
b.child['left'] = Node(2)
b.child['right'] = Node(3)
b.child['left'].child['left'] = Node(4)
#b.child['left'].child['right'] = Node(5)
b.child['right'].child['left'] = Node(6)
b.child['right'].child['right'] = Node(7)
if compare_tree(a, b):
print 'trees are equal'
else:
print 'trees are unequal'
# DFS traversal
traverse_tree(a)
Also pasted an example that you can run.
You may also want to have a look at how git does it. Essentially whenever you do a git diff, under the hood a tree comparison is done.

Algorithm for converting Binary tree to post-fix mathematical expression?

I have a Binary tree for a mathematical expression(infix), i want to convert directly this TREE to a postfix(Stack)
can any body suggest the algorithm?
What you’re searching for is known as post-order tree traversal:
postorder(node)
if node.left ≠ null then postorder(node.left)
if node.right ≠ null then postorder(node.right)
print node.value
Easy, each node is (Left, Right, Data).
Start with the first node. execute the algorithm for the left subtree if available and then execute the algorithm for the right subtree and then print the data.
TreeNode = ([TreeNode], Data, [TreeNode])
TreeToPostfix: [TreeNode] -> Data*
TreeToPostfix(nil) = []
TreeToPostfix((left, data, right)) ==
TreeToPostfix(left) ++ TreeToPostfix(right) ++ Data
For example:
+
/ \
* -
/ \ / \
2 3 4 5
Produces: 2 3 * 4 5 - +

Resources