omd*_*del 4 ruby linked-list data-structures singly-linked-list
在不使用/扩展Array类的情况下在Ruby中实现链表的最佳方法是什么?这是我过去使用的一个实现,但它似乎不是最好的方法:
class Node
attr_accessor :value, :next_node
def initialize(value = nil)
@value = value
end
def to_s
@value
end
end
class SinglyLinkedList
attr_accessor :head
def initialize(first_value=nil)
@head = Node.new(first_value) if first_value
end
def add(value)
#adds a new node to the list, amakes it the new head and links it to the former head
new_node = Node.new(value)
new_node.next_node = @head
@head = new_node
end
def remove
@head = @head.next_node
end
end
Run Code Online (Sandbox Code Playgroud)
fot*_*nus 11
我假设你正在实施这个以进行自我教学,否则它没有任何意义.只是使用Array,这是ruby的列表实现.
在我看来,你应该用C编写这些练习,因为实现链表的重点是更接近机器并更好地理解它是如何工作的.C是一种更好的工具,可以完成这项任务,了解计算机的工作原理.
这就是在大学教授经典链表的方式:O(n)插入,O(n)搜索和O(n)删除.之后,大多数书籍讨论了有关它的改进.
我写了一篇文章,并没有对它进行任何测试,但这应该给你一个想法,并希望能够纠正你发现的任何错误.(更新:@Nitesh发现了一个错字,并修复了它.希望它现在有一些测试).
class Node
attr_accessor :value, :next
def initialize(value = nil)
@value = value
end
def to_s
@value
end
end
class SinglyLinkedList
attr_accessor :head
def initialize(first_value=nil)
@head = Node.new(first_value) if first_value
end
def add(value)
if head.nil?
head = Node.new(value)
else
current_node = @head
while current_node.next
current_node = current_node.next
end
current_node.next = Node.new(value)
end
end
def find(value)
current_node = head
while current_node != nil
return current_node if current_node.value == value
current_node = current_node.next
end
nil
end
def remove(value)
if head.value == value
head = head.next
else
current_node = head.next
prev_node = head
while current_node
if current_node.value == value
prev_node.next = current_node.next
return true
end
prev_node = current_node
current_node = current_node.next
end
nil
end
end
end
Run Code Online (Sandbox Code Playgroud)
我最近遇到了一个有趣的链表实现(不确定哪里不幸),Node该类实现了插入和删除方法.以下是Node双链表的类,但相同的原则适用于单链表.
class Node
protected
attr_writer :prev, :next
public
attr_reader :value, :prev, :next
def initialize(value)
@value = value
end
def remove
@prev.next = @next if @prev
@next.prev = @prev if @next
@next = @prev = nil
end
def insert_after(node)
remove
@next = node.next
@next.prev = self if @next
@prev = node
node.next = self
end
end
Run Code Online (Sandbox Code Playgroud)
我发现这个实现很有趣,因为我发现它非常通用.Node只需要a 就可以开始构建列表并对其进行操作.
head = Node.new(1)
middle = Node.new(2)
middle.insert_after(head)
tail = Node.new(3)
tail.insert_after(middle)
middle.remove
Run Code Online (Sandbox Code Playgroud)
在此实现之上,您可以构建一个非常容易理解的更高级的API.以下是一个LinkedList或更完整版本的Deque.列表本身是子类,Node并链接到列表的头部和尾部.
class ListNode < Node
protected :remove # prevent incorrect access to Node methods
def initialize
@next = @prev = self
end
def head
@next unless @next == self
end
def tail
@prev unless @prev == self
end
def add_to_head(node)
node.insert_after(self)
end
def add_to_tail(node)
node.insert_after(self.prev)
end
def each(&block)
return enum_for(:each) unless block_given?
node = @next
while node != self
yield node
node = node.next
end
end
def to_a
each.collect {|node| node.value }
end
end
Run Code Online (Sandbox Code Playgroud)
以下是它如何在实践中使用:
# create a new list
list = ListNode.new
# add some items to the head or tail
list.add_to_head(Node.new('Hello'))
list.add_to_tail(Node.new('World'))
list.to_a # => ["Hello", "World"]
# remove items from the head
list.head.remove
list.to_a # => ["World"]
list.head == list.tail # => true
# remove items from the tail
list.tail.remove
list.to_a # => []
Run Code Online (Sandbox Code Playgroud)
更好的是each允许我们使用任何Enumerable函数来搜索和遍历节点的方法:
list = ListNode.new
list.add_to_head(Node.new(1))
list.add_to_head(Node.new(2))
list.add_to_head(Node.new(3))
list.add_to_head(Node.new(4))
# list each value
list.each {|node| puts node.value }
# select all nodes with values greater than 2
list.each.select {|node| node.value > 2 }
# find the first node with a value of 4
list.each.find {|node| node.value == 4 }
Run Code Online (Sandbox Code Playgroud)