lua杂记01--链表

这个网站是一个老外的博客,有很多关于lua和love2d的内容,可惜被墙了。这几天也不知道

如何继续love2d,便想着干脆捡一些有用的简单翻译一下,或许能产生点灵感。对于lua而言

我感觉最强大的就是它的table了,有点lisp里的表的感觉。

简译如下,原文在此

作为一个创建自定义数据结构的例子, 我想你得先了解一些关于链表的实现 linkedlists

注意这并不是一篇深入的教程,大部分情况下我会展示一些代码片段。

链表是很好的数据结构,可以完美的实现高效的添加,删除,遍历。唯一的缺点是你不能通过

索引查找元素。

有多种链表,最常见的两种是单链表、双链表。各种链表都有一堆节点,并维持着指向节点之间

的索引。单链表有指向头节点的索引,每个节点都指向下一个节点。双链表有指向头节点和尾节

点的索引,每个节点都指向上一个和下一个节点。若想了解更多,参考Wikipedia page

我决定实现双链表。它的效率稍逊单链表,但是更好用,因为它允许逆向遍历。让我们先来

一段OOP代码。

list = {}
list.__index = list

setmetatable(list, { __call = function(_, ...)
  local t = setmetatable({}, list)
  for _, v in ipairs{...} do t:push(v) end
end })

--译者注:setmetatable设置元表,__call标示table调用时会执行的函数

--这里调用list时就会自动执行__call,__call的内容是先绑定一个空表{},再把参数放入{}。

它允许用户想这样创建链表:

x = list(a, b, c, d)

注意所有的元素都必须是tabel,这样元素才支持索引。(译注:如同c语言里的节点是结构体)。

我展示的第一个函数式简单的 push ,它把元素放到链表的末尾。

function list:push(t)
  if self.last then --如果有节点
    self.last._next = t
    t._prev = self.last
    self.last = t
  else
    --如果是空链表
    self.first = t
    self.last = t
  end
  
  self.length = self.length + 1
end

 

下面是具有相反功能的pop 函数, 它把链表里末尾的元素删除,并返回其值。

function list:pop()
  if not self.last then return end
  local ret = self.last
  
  if ret._prev then
    ret._prev._next = nil
    self.last = ret._prev
    ret._prev = nil
  else
    -- this was the only node
    self.first = nil
    self.last = nil
  end
  
  self.length = self.length - 1
  return ret
end

 

我们使用的更灵活的添加和删除函数式 insertremove:

function list:insert(t, after)
  if after then
    if after._next then
      after._next._prev = t
      t._next = after._next
    else
      self.last = t
    end
    
    t._prev = after    
    after._next = t
    self.length = self.length + 1
  elseif not self.first then
    -- this is the first node
    self.first = t
    self.last = t
  end
end
function list:remove(t)
  if t._next then
    if t._prev then
      t._next._prev = t._prev
      t._prev._next = t._next
    else
      -- this was the first node
      t._next._prev = nil
      self._first = t._next
    end
  elseif t._prev then
    -- this was the last node
    t._prev._next = nil
    self._last = t._prev
  else
    -- this was the only node
    self._first = nil
    self._last = nil
  end

  t._next = nil
  t._prev = nil
  self.length = self.length - 1
end
insert 把节点插入到链表的after节点之后. 如果没指定after, 当链表里没其它节点时,仅添加这个元素。
remove 可以移除链表里的任何元素。
最后是迭代器的实现:
local function iterate(self, current)
  if not current then
    current = self.first
  elseif current then
    current = current._next
  end
  
  return current
end

function list:iterate()
  return iterate, self, nil
end

这仅是顺序迭代,但是实现一个逆向的不难。

到结束的时候了,下面是个使用链表的例子:

require("list")

local a = { 3 }
local b = { 4 }
local l = list({ 2 }, a, b, { 5 })

l:pop()
l:shift()
l:push({ 6 })
l:unshift({ 7 })
l:remove(a)
l:insert({ 8 }, b)
print("length", l.length)
for v in l:iterate() do print(v[1]) end

如果需要全部的代码请git检出 gist #4084042.

 

 

 

 

 

--注,下面即是

list.lua

list = {}
list.__index = list
 
setmetatable(list, { __call = function(_, ...)
  local t = setmetatable({ length = 0 }, list)
  for _, v in ipairs{...} do t:push(v) end
  return t
end })
 
function list:push(t)
  if self.last then
    self.last._next = t
    t._prev = self.last
    self.last = t
  else
    -- this is the first node
    self.first = t
    self.last = t
  end
  
  self.length = self.length + 1
end
 
function list:unshift(t)
  if self.first then
    self.first._prev = t
    t._next = self.first
    self.first = t
  else
    self.first = t
    self.last = t
  end
  
  self.length = self.length + 1
end
 
function list:insert(t, after)
  if after then
    if after._next then
      after._next._prev = t
      t._next = after._next
    else
      self.last = t
    end
    
    t._prev = after    
    after._next = t
    self.length = self.length + 1
  elseif not self.first then
    -- this is the first node
    self.first = t
    self.last = t
  end
end
 
function list:pop()
  if not self.last then return end
  local ret = self.last
  
  if ret._prev then
    ret._prev._next = nil
    self.last = ret._prev
    ret._prev = nil
  else
    -- this was the only node
    self.first = nil
    self.last = nil
  end
  
  self.length = self.length - 1
  return ret
end
 
function list:shift()
  if not self.first then return end
  local ret = self.first
  
  if ret._next then
    ret._next._prev = nil
    self.first = ret._next
    ret._next = nil
  else
    self.first = nil
    self.last = nil
  end
  
  self.length = self.length - 1
  return ret
end
 
function list:remove(t)
  if t._next then
    if t._prev then
      t._next._prev = t._prev
      t._prev._next = t._next
    else
      -- this was the first node
      t._next._prev = nil
      self._first = t._next
    end
  elseif t._prev then
    -- this was the last node
    t._prev._next = nil
    self._last = t._prev
  else
    -- this was the only node
    self._first = nil
    self._last = nil
  end
 
  t._next = nil
  t._prev = nil
  self.length = self.length - 1
end
 
local function iterate(self, current)
  if not current then
    current = self.first
  elseif current then
    current = current._next
  end
  
  return current
end
 
function list:iterate()
  return iterate, self, nil
end
posted @ 2013-03-16 17:03  半山无极  阅读(...)  评论(...编辑  收藏