inserting in linked lists with ruby - ruby

Hi I'm trying to insert a value at a specific index in a linked list in ruby.
Here is my code thus far:
class Node
attr_accessor :data, :pointer, :next
def initialize(data, pointer = nil)
#data = data
#pointer = pointer
end
def next
#data = #pointer
end
end
class LinkedList
attr_accessor :head, :data, :pointer
def initialize(data)
#head = Node.new(data, pointer)
end
def index_at(value_of_index)
current = head
value_of_index.times do
if current.pointer == nil
current = Node.new(nil, nil)
return current = current.data
else
current = current.next
end
end
current.data
end
def insert_at_index(index, value)
current = head
index.times do
current.next
end
current = Node.new(value)
end
end
The problem I've having is with the def insert_at_index method... I can't seem to figure out how to place the new node at the index and value. Any help you can give me would be greatly appreciated.

Say your linked list looks like this:
a -> b -> d -> e
To insert c into the 3rd index, you would move to the second index to get b, create a new node, set b's next to the new node c, and set c's next to the old third index item, d.
This will give you:
a -> b -> c -> d -> e
That said, the code should look like this:
def insert_at_index(index, value)
current = head
# make current b. You may want to put this in a function node_at_index
(index - 1).times do
raise "List not long enough" if current.nil?
current = current.next
end
new_node = Node.new(value) # new node c
new_node.next = current.next # c's next is b's next, d
current.next = new_node # b's next is c
end
From the looks of it there seem to be other issues with your code as well. You're overwriting #data in your next function (you probably meant to just return #pointer), LinkedList#initialize doesn't have pointer defined, etc
You could simplify your Node to look like this:
class Node
attr_accessor :data, :next
def initialize(data, next=nil)
#data = data
#next = next
end
end
Which should work for you.

Here is one solution that worked for me:
class Node
attr_accessor :data, :pointer
alias_method :next, :pointer
def initialize(data, pointer = nil)
#data = data
#pointer = pointer
end
def next
#pointer
end
end
class LinkedList
attr_accessor :head, :data, :pointer
def initialize(data)
#head = Node.new(data, pointer)
end
def index_at(value_of_index)
current = head
value_of_index.times do
if current.pointer == nil
current = Node.new(nil, nil)
return current = current.data
else
current = current.next
end
end
current.data
end
def insert_at_index(index, value)
current = head
(index - 1).times do
if current.pointer != nil
current = current.next
end
end
new_node = Node.new(value)
if current.pointer != nil
new_node.pointer = current.pointer
end
current.pointer = new_node
end
end

Related

Within a Linked List in Ruby, the method add_at with index is not working right

I am studying Ruby, and this Linked list exercise is a little complicated for me, I advanced, but not sure what I am doing wrong:
class Node
attr_accessor :value, :next_node
alias_method :next, :next_node
def initialize(value, next_node = nil)
#value = value
#next_node = next_node
end
def next
#next_node
end
end
class LinkedList
attr_accessor :head, :tail
def initialize
#head = nil
#tail = nil
end
def add(number)
if #head.nil?
new_node = Node.new(number)
#head = new_node
#tail = new_node
else
new_node = Node.new(number)
#tail.next_node = new_node
#tail = new_node
end
end
def get(index)
current = #head
index.times do
current = current.next_node
end
return current.value
end
def add_at(index, item)
current = head
(index - 1).times do
raise "List not long enough" if current.nil?
current = current.next_node
end
new_node = Node.new(item)
new_node.next_node = current.next_node
current.next_node = new_node
end
end
Tried to change the Node method, but seems like that is not the answer
Everything seems fine to me, but the data is not sorted in the right position according the following test:
list = LinkedList.new
list.add(3)
list.add(5)
list.add_at(1, 11)
list.add_at(0, 13)
puts list.get(#)
should be 13,3,11,5 at the end
Am I doing something wrong?
Your LinkedList#add_at method does not work correctly when inserting to the beginning (or end) of the list.
In particular, when calling list.add_at(0, 13), where's what happens:
def add_at(index, item)
current = head # Current is set to the "3" node
(index - 1).times do # This never yields
raise "List not long enough" if current.nil?
current = current.next_node
end
new_node = Node.new(item) # Creates the "13" node
new_node.next_node = current.next_node # "13" points to "11"
current.next_node = new_node # "3" points to "13"
end
Result: Instead of turning 3 --> 11 --> 5 into 13 --> 3 --> 11 --> 5, you've turned it into 3 --> 13 --> 11 --> 5.
In other words, the end result of calling list.add_at(0, 13) is the same as calling list.add_at(1, 13).
I don't want to dictate a single solution to you here; the key takeaway should be how to debug the problem. For example, you could try installing pry, add binding.pry into the method and step through the code to reproduce my summary.
This is an absolutely vital developer skill that's needed to solve problems of this manner.
...But with that said, here's a suggestion: Re-use the existing methods to fetch the previous and next nodes; then re-set the head/tail values if necessary (as well as "inserting" the new node into the list):
def add_at(index, item)
new_node = Node.new(item)
previous_node = get(index-1)
next_node = get(index)
if previous_node
previous_node.next_node = new_node
else
head = new_node
end
if next_node
new_node.next_node = next_node
else
tail = new_node
end
end

Linked List ruby, the Node and LInkedlist class doesnt work properly

I have some issues with this code, so, I'm trying to make a linked list but with the first variable I get the next issue:
nodo.rb:34 in 'initialize': wrong number of arguments(1 for 0)
So, the Node class have the actual node and the link, and LinkedList the size and the header.
The problem comes when I try to add a new value but I receive the issue. So I dont know how to fix this problem. I will receive any help you could give me.
class Node
def intialize(data,ref = nil)
#data = data
#refe = refe
end
def get_data
return #data
end
def set_data(newdata)
#dato = newdata
end
def get_ref
return #ref
end
def set_ref(newref)
#ref = newref
end
end
class Linkedlist
def initialize
#size = 0
#header = nil
end
def add_var(value)
#aize = #size + 1
if #header == nil
#header = Node.new(value) #the issue comes here, in the moment when I try to make a new class of Node
else
nodeActual = #header
while nodeActual.get_ref != nil
nodeActual = nodeActual.get_ref
end
nodeActual.set_ref(Node.new(value))
end
end
#def print_list
#end
def get_size
return #size
end
end
list = Linkedlist.new
stop = nil
while stop != -1
a = gets.chomp
if a.to_i == -1
stop = -1
else
list.add_var(a)
end
end
#list.print_list
you have a typo in Node class, rename intialize to initialize (missing i)

Can't break out of simple while loop

I'm writing a search method for my DoublyLinkedList class as such:
def search(val)
current = #head
while current != nil
if current.node_id == val
return current
else
current = current.prev_node
end
end
return nil
end
However when I try to use this search method I seem to be stuck in the while loop.
Here are my DoublyLinkedList and Node classes for reference:
class Node
attr_accessor :node_id, :next_node, :prev_node
def initialize(node_id)
#node_id = node_id
#prev_node = nil
#next_node = nil
end
end
class DoublyLinkedList
attr_accessor :head, :size
def initialize
#size = 0
#head = nil
end
def add(node)
if #head == nil
#head = node
else
node.prev_node = #head
#head.next_node = node
#head = node
end
#size += 1
end
def search(val)
current = #head
while current != nil
if current.node_id == val
return current
break
else
current = current.prev_node
end
end
return nil
end
end
Here's how I'm testing my method:
linked_list = DoublyLinkedList.new
node1 = Node.new '1'
linked_list.add(node1)
puts linked_list.search(node1.node_id)
Sorry if for such verbosity(?) for such a simple question but I just can't see why my while loop won't break - it should return the found node's node_id!
Try break current instead of return current to get out of a loop.

Ruby Singly Linked List Implementation

I'd like to write an exist function that returns true if a value exists as a node in a linkedlist and returns false otherwise. So far, I have the following code which always returns true. Any help is appreciated:
class SinglyLinkedList
attr_accessor :head, :tail, :count
def initialize
#head = nil
#tail = nil
#count = 0
end
def insert_front(value)
node = Node.new(value)
if #head.nil?
#head = node
#tail = node
else
node.next = #head
#head = node
end
#count +=1
end
def print_first()
puts head.data
end
def print_last()
puts tail.data
end
def exist(value)
walker = #head
until walker.nil?
if walker.data == value
return true
end
walker = walker.next
end
false
end
def size()
count
end
end
class Node
attr_accessor :data, :next
def initialize(data)
#next = nil
#data = data
end
end
This is my test code:
list = SinglyLinkedList.new
list.insert_front(1)
list.exist(2)
which returns true.
Before solution just consider that singly linked list can insert only via append to list. You try to insert nodes in wrong direction.
The problem with you code is that you use reserved method name next, just refactor you code and write simple:
class SinglyLinkedList
class Node
attr_reader :value
attr_accessor :pointer
def initialize(value, pointer = nil)
#value = value
#pointer = pointer
#count = 0
end
end
attr_reader :head, :tail
def initialize
#head = nil
#tail = nil
end
def insert(value)
node = Node.new(value)
#count += 1
if #head.nil?
#head = node
#tail = node
else
#tail.pointer = node
#tail = node
end
end
def inspect
return [] unless #head
values = []
node = #head
begin
values << node.value
node = node.pointer
end while node != nil
values
end
def exists?(value)
return false unless #head
node = #head
begin
node = node.pointer
end while node != nil && node.value != value
node.nil?
end
end

Implement a tree iterator

I created a very simple node class with a name and an array of nodes. I also created an iterator class with a next method that helps me iterate on each node and child nodes. I need to write the next method, but I don't what is the best way to do it.
class Node
def initialize(name, nodes
#name = name
#nodes = nodes
end
end
class Iterator
def initialize(node)
#node = node
end
def next
???
end
end
Example:
z = Node.new("z", [])
b = Node.new("b", [z])
c = Node.new("c", [])
parent = Node.new("a", [b, c])
iterator = Iterator.new(parent)
str = ''
next = iterator.next
while next do
str += next.name
next = iterator.next
end
str should equal "abzc"
Can anybody help me with this?
If I may suggest a more idiomatic approach:
class Node
attr_accessor :name, :children
def initialize(name, children = [ ])
#name = name
#children = children
end
def traverse(&block)
yield self
#children.each { |child| child.traverse(&block) }
end
end
z = Node.new("z")
b = Node.new("b", [z])
c = Node.new("c")
parent = Node.new("a", [b, c])
str = ''
parent.traverse { |node| str += node.name }
puts str
This has a benefit over btilly's solution (which is also correct) in that it doesn't proliferate Iterator objects and suck up memory- in fact Iterator disappears from the implementation (while still retaining the ability to DO something to each node in succession). This is more idiomatic; more Ruby-esque.
In your iterator, if node has any children, next would be the first of them. If it doesn't, then you need to "back up" to the last sibling that you skipped over. This implies that you need to keep track of the siblings that have been skipped over, so that you can go back to them.
Here is some running code that demonstrates what I think you're looking for.
class Node
attr_accessor :name, :nodes
def initialize(name, nodes)
#name = name
#nodes = nodes
end
end
class Iterator
def initialize(node)
#node = node
end
def each_node
yield #node
for node in #node.nodes do
iterator = Iterator.new(node)
iterator.each_node {|next_node|
yield next_node
}
end
end
end
z = Node.new("z", [])
b = Node.new("b", [z])
c = Node.new("c", [])
parent = Node.new("a", [b, c])
iterator = Iterator.new(parent)
str = ''
iterator.each_node {|node|
str += node.name
}
puts str
I have been able to solve my problem by doing the following. But what I don't like with this approach is that I traverse the nodes during the initialization instead of in the next method...
class Iterator
def initialize(node)
#node = node
#index = -1
#list = []
traverse(#node)
end
def next
#index += 1
#list[#index]
end
private
def traverse(root)
#list[#list.size] = root
if root.nodes
for n in root.nodes do
traverse(n)
end
end
end
end

Resources