O(n) time non-recursive procedure to traverse a binary tree - algorithm

I'm reading a book called "Introduction to algorithms". I think many of you know it. I just bumped into a question which seems rather difficult:
Write an O(n)-time nonrecursive procedure that, given an n-node binary tree,
prints out the key of each node. Use no more than constant extra space outside of the tree itself and do not modify the tree, even temporarily, during the procedure.
I saw that there is another question like this: How to traverse a binary tree in O(n) time without extra memory but the main difference is that I can't modify the tree. I was thinking of using some visited flag but I haven't distilled a right solution yet. It's maybe something obvious I don't see. How would you devise an algirithm which solves this problem? Even some pointers to the answer would be appreciated.

If the tree is linked in both directions, you can do this:
assert root.parent is null
now, old = root, null
while now != null:
print now.label
if leaf(now):
now, old = now.parent, now
else:
if old == now.right:
now, old = now.parent, now
if old == now.left:
now, old = now.right, now
if old == now.parent:
now, old = now.left, now
This prints in root, left, right order, but you can get any order you like.
I don't think you can do it if the tree is only linked in one direction. You could have a look at Deforestation.

There is the complete code (in Ruby).
As an example, I have reproduced the same "n-node binary tree" as in the "Introduction to algorithms" book.
class Node
attr_accessor :key, :parent, :left, :right
def initialize(key, parent)
#key = key
#parent = parent
end
end
class Tree
def initialize(root)
#root = root
end
def print_with_constant_space
current, old = #root, nil
while current do
# Going UP
if old && old.parent == current
# Go right if exists
# otherwise continue up
next_node = (current.right || current.parent)
current, old = next_node, current
# Going DOWN
else
puts current.key
# Go left if exists
# otherwise go right if exists
# otherwise go up
next_node = (current.left || current.right || current.parent)
current, old = next_node, current
end
end
end
end
root = Node.new(0, nil)
root.left = (node_1 = Node.new(1, root))
node_1.left = (node_2 = Node.new(2, node_1))
node_2.right = (node_3 = Node.new(3, node_1))
node_3.left = (node_4 = Node.new(4, node_3))
node_1.right = (node_5 = Node.new(5, root))
node_5.left = (node_6 = Node.new(6, node_5))
node_6.right = (node_7 = Node.new(7, node_5))
node_7.right = (node_8 = Node.new(8, node_5))
node_8.left = (node_9 = Node.new(9, node_8))
node_9.right = (node_10 = Node.new(10, node_8))
node_8.right = (node_11 = Node.new(11, node_5))
node_5.right = (node_12 = Node.new(12, root))
node_12.left = (node_13 = Node.new(13, node_12))
tree = Tree.new(root)
tree.print_with_constant_space
I hope it helps...

You will have to do an in-order walk of the tree. In the same book, there is a hint in the first set of exercises on the chapter dealing with Binary Search Trees. To quote:
There is an easy solution that uses a stack as an auxiliary data structure and a more complicated but elegant solution that uses no stack but assumes that two pointers can be tested for equality.
You can find an implementation here: http://tech.technoflirt.com/2011/03/04/non-recursive-tree-traversal-in-on-using-constant-space/

Related

Is it possible to reverse a doubly circular linked list? if Yes, then how?

I am a bit confused, as one of my friend said it not possible. As it's totally symmetric.
I have googled a bit but I am still confused
For each node N of the list, you just need to swap N.next and N.prev. After this, you change the reference of head to be the new head.next. If there is a tail, it should be updated to tail.prev.
Just for better visualization:
Yes; simply swap the previous and next pointers, as well as any head and tail pointers. Can you explain how your friend claims that the list is symmetric?
It is not impossible, it might require some extra care to design the algorithm, but that is with most (all) algorithms where you have to iterate and modify the data structure.
You can simply swap the head and tail, and then iterate over your linked list and swap the next and previous references for each node. You furthermore need to make sure you stop doing that after one full iteration.
A sample algorithm in Python would look like:
class CircularDoubleLinkedList:
# ...
def reverse(self):
self.head, self.tail = self.tail, self.head
start = cur = self.head
if cur is not None:
cur.next, cur.previous = cur.previous, cur.next
cur = cur.previous
while cur is not None and cur is not start:
cur.next, cur.previous = cur.previous, cur.next
cur = cur.previous # move to the next node

Extending (Monkey Patching) a Binary Search for Array Class and Syntactic Sugar

I've been studying a few searching algorithms and my last problem comes down to binary searching. I watched a few youtube videos to understand the concept and then tried to solve the problem, but keep getting an endless loop error. I've looked through stack overflow, and reddit, and wherever Google would lead me, but I can't quite find a solution that fits my method of coding. Also, please excuse the term 'monkey patching', it's been brought to my attention that the technical term is called 'extending' so the fault lies on my instructors for teaching it to us as 'monkey patching'.
Here's my code:
class Array
def my_bsearch(target)
return nil if self.empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx + 1)
return middle_idx if self[middle_idx] == target
until self[middle_idx] == target || self.nil? == nil
if self[middle_idx] < target
right.my_bsearch(target)
elsif self[middle_idx] > target
left.my_bsearch(target)
end
end
end
end
I have a solution, but I don't want to just memorize it-- and I'm having trouble understanding it; as I'm trying to translate it, learn from it, and implement what I'm missing into my own code.
class Array
def my_bsearch(target)
return nil if size == 0
mid = size/2
case self[mid] <=> target
when 0
return mid
when 1
return self.take(mid).my_bsearch(target)
else
search_res = self.drop(mid+1).my_bsearch(target)
search_res.nil? ? nil : mid + 1 + search_res
end
end
end
I guess I understand case/when despite not use to using it. I've tried following it with debugger, but I think I'm hung up on what's going on in the ELSE section. The syntactic sugar, while making this obviously more concise than my logic, isn't straight-forward/clean to someone of my ruby literacy level. So, yeah, my ignorance is most of the problem I guess.
Is there someone who is a little more literate, and patient, able to help me break this down into something I can understand a bit better so I can learn from this?
First, take and drop have sufficiently similar interfaces that you don't actually want your + 1 for drop. It will disregard one element in the array if you do.
Next, self.nil? will always be false (and never nil) for instances of this class. In fact, .nil? is a method exactly to avoid having to ever compare against nil with ==.
You want self.empty?. Furthermore, with the exception of setters, in Ruby messages are sent to self by default. In other words, the only time self. is a useful prefix is when the message ends in = and operates as an lvalue, as in self.instance_var = 'a constant', since without the self., the tokens instance_var = would be interpreted as a local variable rather than an instance variable setting. That's not the case here, so empty? will suffice just as well as self.empty?
So I figured it out, and I decided to answer my own post in hopes to help someone else out if they run into this issue.
So, if I have an Array and the target is the middle_element, then it will report middle_element_idx. That's fine. What if the target is less than middle_element? It recursively searches the left-side of the original Array. When it finds it, it reports the left_side_idx. There's no problem with that because elements in an array are sequentially counted left to right. So, it starts at 0 and goes up.
But what if the target is on the right side of the middle element?
Well, searching for the right side is easy. Relatively the same logic as searching left. Done recursively. And it will return a target_idx if it's found on that right side --however that's the target's idx as it was found in the right-side array! So, you need to take that returned target_idx and add 1 to it and the original middle_element_idx. See below:
def my_bsearch(target)
return nil if self.empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx + 1)
if self[middle_idx] == target
return middle_idx
elsif self[middle_idx] > target
return left.my_bsearch(target)
else
searched_right_side = 1 + right.my_bsearch(target)
return nil if searched_right_side.nil? == true
return searched_right_side + middle_idx
end
end
end
Notice how many more lines this solution is? The spaceship operator used in conjunction with case/when and a ternary method will reduce the number of lines significantly.
Based on suggestions/feedback from Tim, I updated it to:
def my_bsearch(target)
return nil if empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx)
if self[middle_idx] == target
return middle_idx
elsif self[middle_idx] > target
return left.my_bsearch(target)
else
searched_right_side = right.my_bsearch(target)
return nil if searched_right_side.nil?
return searched_right_side + middle_idx
end
end
end

'pop' method in Ruby

I've created a 'pop' method to take the last node off of a linked list. However, the issue I'm receiving is that it's not removing the node, it's simply telling me the data in the node that should be removed.
I should preface with I'm using test driven development and the test was written to say 'assert_equal "blop", list.pop. "blop" is the value of the last node. It's great that I got my method to tell me that, but it still doesn't remove the node.
def pop
#count -= 1
return_string = ""
current_node = #head
until current_node.next_node == nil
current_node = current_node.next_node
end
return_string << current_node.data + " "
return_string.strip
current_node.next_node = Node.new(data)
end
My question is how do I return the value of what's being removed, as well as, removing the value from the linked list.
until current_node.next_node == nil
current_node = current_node.next_node
end
When that loop finishes, current_node is pointing to the last node (the node for which the next node is `nil).
That's the node you should remove, but in order to remove that one, you should point the previous node's next_node to nil.
However, at that point you don't have a reference to the previous node.
You could have another variable to track the previous node so that you can then remove it once you exit the loop.
You can check this related question (not Ruby specific) for ideas on the algorithm.
Linked List implementation for a stack
As a side note, one of the answers on that one implements this as making pop remove the first node of the list (and push add the node to the beginning), which makes it easier (and faster, since you don't go over the whole list each time).

problems implementing negamax for tic-tac-toe in ruby

I'm banging my head against the wall trying to implement negamax for tic-tac-toe
def negamax(board_obj, mark, depth)
if board_obj.game_over?
return value(board_obj)
else
max = -1.0/0 # negative infinity
if mark == #mark
next_mark = #opponent_mark
else
next_mark = #mark
end
board_obj.empty_squares.each do |square|
board_obj[square] = mark
x = -negamax(board_obj, next_mark, depth + 1)
board_obj[square] = ' '
if x > max
max = x
#scores << x
#best_move = square if depth == 1
end
end
return max
end
end
# determines value of final board state
def value(board_obj)
if board_obj.mark_win?(#mark)
return 1
elsif board_obj.mark_win?(#opponent_mark)
return -1
else
return 0
end
end
the rest of the code is here: https://github.com/dave-maldonado/tic-tac-doh/blob/AI/tic-tac-doh.rb
It does produce a result but the AI is easily beat so I know something's wrong, any help
is appreciated!
The problem is that value needs to be relative to the mark in the current execution of negamax rather than always relative to the computer. If you pass in the mark argument to value from negamax with the following modified definition for value, you'll get the right results:
def value(board_obj, mark)
if board_obj.mark_win?(mark)
return 1
elsif board_obj.mark_win?(mark == 'X' ? 'O' : 'X')
return -1
else
return 0
end
end
That is, the first two lines of the negamax body need to be:
if board_obj.game_over?
return value(board_obj, mark)
That said, this overall program leaves an awful lot to be desired relative to Ruby, good design principles, etc (no offense intended). Now that you have it running, you might want to head over to the Code Review SE for some feedback. :-) And while it's too late to use TDD ;-), it would also be a good one to put "under test".
Also, please understand that per one of the other comments, this is not a kind of question that you'll typically get an answer to here at SO. I don't even know if this question will survive the review process without getting deleted. I worked on it for a variety of personal reasons.
Update: Looking at your reference implementation, you'll note that the negamax code includes the expression sign[color]*Analysis(b). It's that sign[color] that you were missing, effectively.

Recursively Searching in a Tree

I'm working with the Stanford Parser in ruby and want to search for all nodes of a tree with a particular label name.
This is the recursive method i have coded so far
def searchTreeWithLabel(tree,lablename,listOfNodes)
if tree.instance_of?(StanfordParser::Tree)
if tree.lable.toString == lablename then
listOfNodes << tree
else
tree.children.each { |c| searchTreeWithLabel(c, lablename, listOfNodes)}
end
end
listOfNodes
end
i want the method to return a list of Tree nodes that have the label as labelname
I'm not familiar StanfordParser but I imagine you need to take the descent part of the traversal out of the inner conditional and always do it.
Also, did they really implement a toString method? Seriously? It's not .to_s? I mean, I enjoyed Java, before I found Ruby... :-)
my original code was correct but ruby was having some problem with the
if tree.lable.toString == lablename then
statement, turns out tree.value works as well, so now i'm checking
if tree.value == lablename then
and it works.

Resources