Ruby背景:什么是链表?

时间:2014-09-19 20:57:48

标签: ruby data-structures

我是一名自学成才的程序员,并从Ruby开始。我目前正在尝试学习算法和数据结构,并注意到一些称为链表的东西。看起来Ruby没有那个数据结构(可能在Array?)。我熟悉数组和哈希。

您如何描述/解释来自我背景的人的链接列表是什么?

2 个答案:

答案 0 :(得分:2)

链接列表相当简单:它们是通过将元素链接在一起而创建的列表。 (有点显而易见,当你想到它时,不是吗?)

在最基本的形式中,链表只是空或一对。该对的第一个元素是一个值,该对的第二个元素是一个表示其余值的链表。

传统上,该对称为 cons cell ,第一个元素称为 head car 列表和第二个元素element被称为列表的 tail cdr 。空列表名为Nil或简称[]

这是Ruby中链接列表的一个非常简单的实现,它只使用函数来实现链接列表(以及布尔值和条件,而我们还在其中):

True   = ->(iff, _) { iff }
False  = ->(_, els) { els }

Pair   = ->(first, rest) { -> x { x.(first, rest) }}
First  = -> list { list.(True ) }
Rest   = -> list { list.(False) }

在这里,我们有一个包含三个元素的简单列表:

List   = Pair.(1, Pair.(2, Pair.(3, nil)))

First.(Rest.(List))
# => 2

更真实的面向对象的列表编码如下所示:

class List
  def cons(el) Pair.new(el, self) end

  Empty = new

  class Pair < self
    attr_reader :first, :rest

    def initialize(first, rest=Empty)
      self.first, self.rest = first, rest
    end

    private

    attr_writer :first, :rest
  end
end

同样,列表包含两个元素:

list1 = List::Pair.new(1, List::Pair.new(2, List::Pair.new(3, List::Empty)))
# corresponds to the list [1, 2, 3]

list1.rest.first
# => 2

list2 = List::Empty.cons(6).cons(5).cons(4)
# List[4, 5, 6]

list2.rest.first
# => 5

更完整和Rubyish的实现可能如下所示:

class List
  include Enumerable

  def self.[](*els) els.reverse_each.inject(Empty, &:cons) end

  def cons(el) Pair[el, self] end

  def prepend(prefix)
    case
    when        empty? then prefix
    when prefix.empty? then self
    else prepend(prefix.rest).cons(prefix.first)
    end
  end

  def to_s; "List[#{map(&:to_s).join(', ')}]" end
  def inspect; "List[#{map(&:inspect).join(', ')}]" end

  def each; return enum_for(__method__) unless block_given? end

  class << Empty = new
    def empty?; true end
    alias_method :inspect, def to_s; 'Empty' end

    freeze
  end
  Empty.freeze

  class Pair < self
    def initialize(first, rest=Empty)
      self.first, self.rest = first, rest
      freeze
    end

    def empty?; false end

    def each(&blk)
      return super unless block_given?
      yield first
      rest.each(&blk)
    end

    private
    attr_writer :first, :rest

    protected
    attr_reader :first, :rest

    class << self; alias_method :[], :new end

    freeze
  end

  freeze
end

一些例子:

list1 = List::Pair[1, List::Pair[2, List::Pair[3, List::Empty]]]
# => List[1, 2, 3]

list2 = List::Empty.cons(6).cons(5).cons(4)
# => List[4, 5, 6]

list3 = List[7, 8, 9]
# => List[7, 8, 9]

list4 = list3.prepend(list2).prepend(list1)
# => List[1, 2, 3, 4, 5, 6, 7, 8, 9]

list4.partition(&:odd?)
# => [[1, 3, 5, 7, 9], [2, 4, 6, 8]]

答案 1 :(得分:1)

在计算机科学中,链表是由一组节点组成的数据结构,这些节点一起表示序列。在最简单的形式下,每个节点由数据和到序列中下一个节点的引用(换句话说,链接)组成;更复杂的变体添加其他链接。该结构允许从序列中的任何位置有效插入或移除元素。 http://en.wikipedia.org/wiki/Linked_list

以下是ruby的实现:http://matt.weppler.me/2013/08/14/implementing-a-linked-list-in-ruby.html

感谢Ruby学习我最喜欢的语言之一。