如果您熟悉数据结构,则可能听说过LinkedList 。
在本文中,我们将从头开始创建一个LinkedList,并说明此数据结构如何工作以及它的用途。
让我们首先说明链接列表的概念。
简单来说,LinkedList是一种由数据集合组成的数据结构。
LinkedList中的值表示节点,每个节点包含一个指向下一个节点的指针。 在LinkedList中,每个节点的数据可以是任何数据。 我们称第一个节点为头,最后一个为尾。
此数据结构类似于数组,因为我们可以将两者都用于存储线性数据。 尽管它们之间存在一些差异,但让我们深入研究它。
首先,在LinkedList中,检索元素的Big O时间复杂度为0(n)。 原因是,对于链表,我们无法像数组一样通过索引来检索元素。
我们需要从头开始遍历该列表,直到找到要检索的元素。
此时,您可能会认为最好使用数组而不是LinkedList。 因为我们在使用数组访问元素时具有更好的运行时复杂性。
现在让我们谈谈删除和插入。
数组中的这些操作消耗大量时间。 另一方面,LinkedList中这些操作的执行速度很快。 同样,数组的大小固定,链接列表是动态的,可以扩展其大小。
最终,链表需要比数组更少的内存空间。
![](https://i-blog.csdnimg.cn/blog_migrate/ed7600023a558a064a98c665c84c7c6c.png)
现在,我们准备开始实施链接列表…
首先,我们将创建节点类,该类将帮助我们将新节点追加到“链接”列表中。
class Node
attr_accessor :value , :next_node
def initialize (value, next_node = nil )
@value = value
@next_node = next_node
end
end
现在我们有了Node类,我们可以创建LinkedList类。
class LinkedList
attr_accessor :tail , :head
def initialize
@head = nil
@tail = nil
end
end
对于我们的LinkedList类,我们还定义了两个访问器(tail,head)。 头部将是LinkedList中的第一个元素,而尾部将是最后一个元素。
我们还使用了构造函数方法来分配初始值。
这是创建LinkedList的基本设置,要对其进行测试,我们可以创建LinkedList类的实例。
list = LinkedList . new
puts list
然后在控制台中运行我们的ruby文件并查看输出。
user@PC/desktop/ Ruby: ~$ ruby linked_list.rb
#<LinkedList:0x00000000051ff9a0>
现在,我们可以创建第一个方法来向LinkedList添加新元素。 我们将从添加add_first方法开始。
def add_first (data)
@head = Node.new(data, @head)
end
现在,通过这种方法,我们可以在LinkedList的开头添加元素。 由于我们将@head设置为新节点,因此我们将数据和@head传递为第二个参数。 结果是该元素将被插入列表的第一个位置。
现在创建一个新方法,将其追加到列表的末尾。
def add_last (data)
node = Node.new(number)
if !@head
@head = node
@tail = node
return
end
last_node = get_last()
last_node.next_node = node
@tail = node
end
private
def get_last
return if !@head
node = @head
until node.next_node. nil ?
node = node.next_node
end
return node
end
在这种情况下,我们有两种方法。 一个有助于获取最后一个节点,该节点是私有的,另一个则将节点添加到列表的末尾。 在第一种方法中,我们首先创建一个新节点并传递数据。
然后,我们检查@head是否为nil,是否将@head和@tail设置为新节点并返回,以便执行停止。 如果@head不为nil,则通过调用get_last方法获得最后一个节点。 然后将next_node设置为新节点,最后,我们将该节点分配给@tail。
很好,现在我们可以将新元素添加到列表的末尾和前面。 但是我们可以通过创建将元素追加到特定位置的方法来做得更好,让我们看看如何做到这一点。
def add_at (index, data)
if !@head
@head = Node.new(data)
return
end
if index == 0
add_first(data)
return
end
previous = get_node(index — 1 ) || get_last()
node = Node.new(data, previous.next_node)
previous.next_node = node
end
private
def get_node (index)
return if !@head
return @head if index === 0
node = @head
counter = 0
until node.next_node. nil ?
node = node.next_node
counter+= 1
return node if counter === index
end
end
同样,这里还有另一个私有方法,可以帮助我们在特定索引处获取节点。 在add_at方法中,我们获取索引和数据,如果@head为零 ,则将@head分配给新节点。 然后返回以停止执行。 如果 @head不为nil,则检查索引是否等于0,如果索引为0,则调用add_first方法并传递数据。 这样,我们就可以重用始终是一个好习惯的方法。
然后,如果索引不为0,则创建一个名为previous的变量,并将其分配给get_node或get_last方法的结果值。 如果其中一个返回nil,则前一个变量将采用另一个方法的值。 然后,我们创建一个新节点并将数据和previous.next_node作为第二个参数传递。 最后,我们将previous.next_node分配给刚创建的节点。
现在我们基本上可以将元素添加到列表中的任何特定位置了。
我们将执行相同的操作以删除元素。 我们将使用三种方法remove_first , remove_last和remove_at 。
def remove_first
return nil if !@head
@head = @head.next_node
end
def remove_last
return nil if !@head
if !@head.next_node
@head = nil
return
end
prev = @head
node = @head.next_node
while node.next_node do
node = node.next_node
prev = prev.next_node
end
@tail = prev
prev.next_node = nil
end
def remove_at (index)
return if !@head
if index == 0
@head = @head.next_node
return
end
previous = get_node(index- 1 )
if !previous || !previous.next_node
return
end
previous.next_node = previous.next_node.next_node
end
这三种方法遵循与我们过去附加的逻辑相同的逻辑。 唯一的区别是操作(删除/添加)。
最后,我们想要获取第一个元素,清除我们的LinkedList并获取大小,让我们放置这些方法。
def clear
@head = nil
@tail = nil
end
def size
return 0 if !@head
node = @head
counter = 0
while node do
node = node.next_node
counter += 1
end
counter
end
def get_first
@head.value
end
在clear方法中,我们只将@head和@tail分配给nil。 满容易。 在get_first方法中,我们返回@head的值。 在size方法中,我们遍历头部并创建一个计数器,直到节点为nil,然后返回该计数器。 真的也很简单。
太棒了,我们已经用不同的方法实现了链表数据结构。
![](https://i-blog.csdnimg.cn/blog_migrate/c78409b3f20cae57f03e5540edafa4fb.png)
从那以后,LinkedList是一个很棒的数据结构,可以在计算机中实现。 也有队列和堆栈。 了解它的工作原理非常重要,因为许多应用程序使用链表来存储数据,因为它们可以执行数组无法执行的恒定操作。
在此处查看LinkedList的不同用法。
在现实世界中,数据结构使用的内存空间可能会确定巨大的变化。 这就是为什么LinkedList在某些情况下如此有用的原因。 重要的是要知道在某些情况下使用数组更好,因此一切都取决于您的需求。
希望您喜欢并学到一些新东西,如果喜欢可以分享这篇文章,并感谢您的阅读。
From: https://hackernoon.com/understanding-linkedlist-data-structure-in-ruby-4q653yqo