I am implementing a reversed linked list using a stack.
Class Stack has methods push and pop, which turn a linked list into a stack from which the last element can be extracted in order to reverse the order.
I've encountered a similar situation here, and I'm trying to add a method to that base case. I'm trying to implement a reverse_list method that makes use of the Stack class's push and pop in order to change the pointer and reverse the linked list.
This is what I tried:
class LinkedListNode
attr_accessor :value, :next_node
def initialize(value, next_node=nil)
#value = value
#next_node = next_node
end
end
def print_values(list_node)
if list_node
print "#{list_node.value} --> "
print_values(list_node.next_node)
else
print "nil\n"
return
end
end
class Stack
attr_reader :data
def initialize
#data = nil
end
def push(value)
#data = LinkedListNode.new(value, #data)
end
def pop
return nil if #data.nil?
returning_value = #data.value
#data = #data.next_element
returning_value
end
end
def reverse_list(list)
stack = Stack.new.push(list.value)
list = list.next_node
while list
stack.push(list.value)
list = list.next_node
end
stack.pop
end
node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)
revlist = reverse_list(node3)
print_values(revlist)
# should return 37 --> 99 --> 12 --> nil
I get errors when calling the Stack class in the reverse_list method (undefined method push for <Context::LinkedListNode:0x00000001c5e0a8>).
I'm at a loss as to why I cannot use Stack, push, and pop inside reverse_list. Any tips as to how I could go about implementing reverse_list will be well received.
The following pushes the elements into the stack, and then reverses them:
def reverse_list(list)
stack = Stack.new
while list
stack.push(list.value)
list = list.next_node
end
LinkedListNode.new(stack.pop, stack.data)
end
stack = Stack.new.push(list.value)
In your example, variable stack is an instance of LinkedListNode as push method is returning instance of linked list. So no method error is throwing. You have to create instance of Stack first like stack = Stack.new which woulb be an empty stack and then do push and pop operation using this instance.
Your pop Method within your Stack class is calling for "next_element", but I think you should be referring to the "next_node" variable from the LinkedListNode class. I would re-write your "pop" method this way:
def pop
if #data.nil?
nil
else
returning_value = #data.value
#data = #data.next_node
returning_value
end
end
I would also rewrite the method to reverse the linked list like this:
def reversed_linked_list(list)
stack = Stack.new
while list
stack.push(list.value)
list = list.next_node
end
LinkedListNode.new(stack.pop, stack.data)
end
Iterate through the list adding its contents to a stack until the end of the list. After that, the following algorithm can be applied.
root = stack.pop() # last element
current = root
while not stack.empty(): # move in reverse direction
current.next = stack.pop() # next element in stack is the next node
current = current.next # continue to the next node
current.next = nil # mark end of the list
Related
So im going through the OdinProject and starting on the "BinaryTree" portion. I've written a Binary Tree but only in C++ using pointers. So without pointers it's a little more confusing to me at how the nodes connect:
class Node
attr_accessor :value, :parent, :left, :right
##nodes = 0
def self.nodes
##nodes
end
def initialize(value, parent=nil)
#value = value
#parent = parent
#left = nil
#right = nil
##nodes += 1
end
end
class BinaryTree
def initialize
#root = nil
end
def build_tree(arr)
arr.each {|el| add_child(el,#root)}
#root
end
def add_child(value,node)
if #root.nil?
#root = Node.new(value)
else
if value < node.value
node.left.nil? ? node.left = Node.new(value,node) : add_child(value,node.left)
elsif value > node.value
node.right.nil? ? node.right = Node.new(value,node) : add_child(value,node.right)
end
end
return node
end
end
I've done some basic print functions, and it SEEMS to be working correctly, but I was wondering if this looks correct to others that understand ruby better. (Sidenote: I realize this does not handle duplicate numbers). Am I missing something with the "building" portion of the tree.
The reason im concerned is a see a lot of different "build" implementations. One that starts at the midpoint for instance, or is this just for "Sorted" arrays?
welcome to the ruby world! Beware you might really like it and never come back to another language :)
Here are some comments I can give you:
Testing
First thing when you wonder if your code is correct is to test it with different inputs. You can do it by hand, in the console, or you can write tests that will follow you during the development.
By printing
A quick way of testing what you do is to define the to_s method on your Node class. For instance, this will allow to check your tree is ordered:
class Node
…
def to_s
"#{left} #{value} #{right}".strip
end
end
to_s is the default ruby method used when converting an object to a string. You can for instance do:
#> puts BinaryTree.new.build_tree([5, 9, 1, 6])
1 5 6 9
By testing
For your peace of mind, you can describe some tests that will allow you to write code, and modify it, and check it is still working. I would suggest minitest for doing it easily.
require 'minitest/autorun'
describe BinaryTree do
before do
#constructor = BinaryTree.new
end
describe 'when given an array' do
it 'sorts it' do
#constructor.build_tree([1, 3, 2]).to_s.must_equal '1 2 3'
end
end
describe 'when given an array with duplicates' do
it 'builds the correct tree' do
#constructor.build_tree([1, 3, 2, 3]).to_s.must_equal '1 2 3 3'
end
end
end
You can then run it with ruby -Ilib:test binary_tree.rb if binary_tree.rb is the file where you put your code.
You will see there, as you mentioned, that the duplicate code doesn’t work.
You can make it work by removing a condition in the if…elsif block.
Then you wan work on the code and run the test as often as you like so that you are confident you didn’t break anything.
Each time you have an edge case you are not sure your code handles, just put that in a test.
Counting the nodes
Your Node.nodes method is probably not what you want if it is supposed to count the number of nodes in your binary tree.
It should be in the instance of a Node, not in the class itself: if you have several trees, all nodes are taken into account for each tree.
Ruby things
Some of the things you write could be expressed differently in ruby:
Nil is not necessary
attr_accessor parent is syntactic sugar for
def parent
#parent
end
def parent=(other)
#parent = other
end
In ruby if your instance variable #parent is not declared, it has the value nil by default, and calling node.parent will return nil too.
You don’t need these 2 lines in the initializer:
#left = nil
#right = nil
Return is not necessary
When your last instruction in a method is a return, you don’t need the return keyword. That is what I did with the to_s method above.
Named parameters
I think it is cleaner to have named parameters when they are not obvious.
For instance, calling Node.new(value, node) doesn’t really help understanding what are these 2 parameters for. I get that a node should have a value, but what is this second parameter?
You could define:
def initialize(value, parent: nil)
# Same as before
end
and call it with Node.new(value, parent: node), or Node.new(value)
OO things
Moving methods where they belong
Your BinaryTree#add_child method should be on a node. You are adding a child to the node. Move it there, so you don’t need your second parameter:
add_child(value, node.right) becomes node.right.add_child(value)
class Node
...
def add_child(other_value)
if other_value < value
left.nil? ? self.left = Node.new(other_value, parent: self) : left.add_child(other_value)
else
right.nil? ? self.right = Node.new(other_value, parent: self) : right.add_child(other_value)
end
end
end
class BinaryTree
...
def add_child(value)
if #root.nil?
#root = Node.new(value)
else
#root.add_child(value)
end
#root
end
end
While you are there you could also get rid of build_tree in the BinaryTree class, and move it to the Node.
I hope it will help you in your Ruby Journey.
I'm trying to implement a singly linked LinkedList in Ruby and I'm having some trouble trying to figure out why some of the nodes are disappearing. Here's what I have so far:
class Node
attr_accessor :data, :next
def initialize(data)
#data = data
end
end
class LinkedList
attr_accessor :head
def insert(data)
node = Node.new(data)
if #head.nil?
#head = node
else
travel = #head
unless travel.next.nil?
travel = travel.next
end
travel.next = node
end
print #head
end
def to_string
result = ""
travel = #head
unless travel.nil?
result << "#{travel.data} => "
travel = travel.next
end
result << "END"
result
end
end
And here is a call to this class:
list = LinkedList.new
list.insert(5)
list.insert(6)
list.insert(7)
At the end of insert, I print out #head and I can see that all three nodes are in the list. However, when I make a separate call to to_string, #head only has the first node but everything else is gone. Can anyone point me in the right direction to what's wrong?
Thanks!
There is a problem with the keyword unless. In ruby, it is a conditional statement, just like if. It is not a loop. Just replace them with the keyword until.
About the linked list in general, the point of it is to make insertion in O(1), whereas you are doing it in O(n) (traverse the list and insert the node at the end). Instead, you can just insert the new node at the beginning, it will be ok.
Finally, ruby's convention is to name the to_string method to_s, so it will be called when printing the list.
Also, you have the possibility of making Node an internal class of LinkedList. It will be useful if you want to implement other node-based data structures (deque, ring, tree, etc)
def initialize_sign_in_guard_stack
default_guard = DefaultSignInGuard.new(self)
guards = Clearance.configuration.sign_in_guards
guards.inject(default_guard) do |stack, guard_class|
guard_class.new(self, stack)
end
end
class DefaultSignInGuard < SignInGuard
def call
if session.signed_in?
success
else
failure default_failure_message.html_safe
end
end
end
class SignInGuard
def initialize(session, stack = [])
#session = session
#stack = stack
end
private
attr_reader :stack, :session
def signed_in?
session.signed_in?
end
def current_user
session.current_user
end
end
Pry(main)> Clearance.configuration.sign_in_guards # => []
No. 1
Since guards is an empty array, so what the guard_class refers to?
And how could it run the new method? Can you explain what does this line of code do?
No. 2
signed_in? is a private method of SignInGuard. I know that only 'self' can
call it. Here, session.signed_in? Why does it make sense?
No1: To nothing. The block will never execute when you call it on an empty array, therefore a value will not be assigned. It is like asking what is item in [].each { |item| puts item }. The idea is when it is not empty to create objects of a list of guard classes. Then guard_class will refer to each individual guard class.
No2: You can't call private methods with explicit receiver, even if it is self. However, here signed_in? called on session is Session#signed_in?, not SignInGuard#signed_in?, which is public so it is fine.
My Code
def property_values_list
property_values = {"ceremonial"=>249, "party"=>250, "wedding"=>251, "casual"=>252}
end
$property_values = property_values_list()
class Design
attr_reader :occasion_ids
def occasion_ids=(property_name)
self.occasion_ids = []
self.occasion_ids << $property_values[property_name]
end
end
d = Design.new
d.occasion_ids = 'party'
Error
SystemStackError: stack level too deep
from .rvm/rubies/ruby-1.9.3-p545/lib/ruby/1.9.1/irb/workspace.rb:80
Maybe IRB bug!
That is not a bug, it is just a infinite recursion, because you do a call to assign method occasion_ids= from the method itself:
def occasion_ids=(property_name)
self.occasion_ids = []
Do assigning to an instance variable:
def occasion_ids=(property_name)
#occasion_ids = []
I tried to write a quick implementation for a binary search tree in Ruby, which is a data structure I commonly write when learning a new programming language.
I get stack too deep errors when I run it on my computer. I wonder if it is an issue with my code or perhaps how I'm running it?
class Node
attr_accessor :data, :left, :right
def initialize(d)
#data = d
#left = Node.new(nil)
#right = Node.new(nil)
end
end
class BST
attr_accessor :root
def initialize
#root = nil
end
def add_recursive(r, d)
if r == nil
r = Node.new(d)
else
add_recursive(r.right, d) if d > r.data
add_recursive(r.left, d) if d < r.data
end
end
def add(darg)
add_recursive(#root, darg)
end
def pr(r)
if (r.left != nil)
pr(r.left)
end
print "#{r.data}"
if (r.right != nil)
pr(r.right)
end
end
end
bb = BST.new
bb.add(100)
bb.add(0)
bb.add(-100)
bb.pr(bb.root)``
I was wondering what am I doing wrong in this implementation because I did indeed run a few simple tests and my use in accessing the data variable was giving me problems. Thanks for any help
You've got more than one problem here, but your infinite recursion is occurring with your first Node.new(nil) call in Node#initialize. Another problem is that you never update #root in BST after you initialize it to nil. In add_recursive your assignment to r has no effect on #root.