Programming in Lua, 2Nd Edition - Chapter 11: Data Structures

 

 

 

 

Chapter 11: Data Structures

 

所有其它语言提供的数据结构 —— 数组,记录,链表,队列,sets  都可以用lua table 来表示。

 

传统的语言如C Pascal,我们用得最多的数据结构是数组和链表(这里链表=记录+指针)。虽然我们可以将数组和链表用Lua 的表来实现(有时我们会这样做),表比数组和链表更强大。利用表使得许多算法的元素遍历得到简化,例如,我们很少写搜索算法,因为表提供了对任意类型的直接访问。

 

接下来将展示如何使用表来实现典型的数据结构,我们先从数组和链表开始。这不是因为我们需要它们,而是因为多数程序员对它们熟悉。

 

 

11.1 Arrays

 

创建数组

 

a = {} -- new array

for i=1, 1000 do

         a[i] = 0

end

print(#a) --> 1000  -- #计算数组长度

 

创建拥有负数和零索引数组

 

-- creates an array with indices from -5 to 5

a = {}

for i=-5, 5 do

       a[i] = 0

end

 

但是,通常lua 1 作为数组的起始索引,Lua 库也是如此。如果你的数组不遵循这种习惯就不能很好的使用库。

 

在构造器中初始化数组

 

squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}

 

构造器的列表可以任意长(可以大到数百万元素)。

 

 

11.2 Matrices and Multi-Dimensional Arrays

 

Lua 中主要有两种方法来表示矩阵。第一种是使用嵌套数组,就是一个表中的每个元素是另一个表。

 

创建N*M 矩阵

 

N, M = 2, 2

mt = {} -- create the matrix

for i=1,N do

       mt[i] = {} -- create a new row

       for j=1,M do

              mt[i][j] = 0

       end

end

 

如果把for j=1,M do 改成for j=1,i do 创建的就是三角矩阵。这三角矩阵的元素比原矩阵少一半?。

 

 

表示矩阵的第二种方法是通过将两个索引合并成一个索引。如果两个索引是整数,你可以给第一个乘以一个常量并加上第二个索引。

 

mt = {} -- create the matrix

for i=1,N do

       for j=1,M do

              mt[(i-1)*M + j] = 0

       end

end

 

如果索引是字符串,可以把两个索引连接起来,并在中间连接一个分隔符,作为单一索引。

 

通常,应用程序使用稀疏矩阵,这种矩阵内部元素多为0 nil。例如,你可以通过邻接矩阵来表示图。


 

遍历矩阵

 

function mult (a, rowindex, k)

       local row = a[rowindex]

       for i, v in pairs(row) do

              row[i] = v * k

       end

end

 

注意,这些索引在表中没有内在的顺序,pairs 不保证以升序访问各个列。某些情况下这不成问题,但其它情况下你需要用别的方法,如链表。

 

 

11.3 Linked Lists

 

list = nil

list = {next = list, value = v}

local l = list

while l do

       <visit l.value>

       l = l.next

end

 

 

11.4 Queues and Double Queues

 

Lua 中实现队列的方法是使用insert remove。这些函数可以在数组的任意位置插入和移除元素,还可以移动元素。但是,对于大的结构这些移动代价太高。一个更高效的实现是使用索引,一个索引对应第一个元素,另一个索引对应最后一个元素。

 

function ListNew ()

       return {first = 0, last = -1}

end

 

为避免污染全局空间,我们将在表的内部定义所有操作(在表内存函数指针)

 

List = {}

function List.new ()

       return {first = 0, last = -1}

end

 

function List.pushfirst (list, value)

       local first = list.first - 1

       list.first = first

       list[first] = value

end

 

function List.pushlast (list, value)

       local last = list.last + 1

       list.last = last

       list[last] = value

end

 

function List.popfirst (list)

       local first = list.first

       if first > list.last then error("list is empty") end

       local value = list[first]

       list[first] = nil -- to allow garbage collection

       list.first = first + 1

       return value

end

 

function List.poplast (list)

       local last = list.last

       if list.first > last then error("list is empty") end

       local value = list[last]

       list[last] = nil -- to allow garbage collection

       list.last = last - 1

       return value

end

 

现在,我们可以在常量时间内插入和删除元素。

 

因为Lua 用双精浮点表示数值,使用这个结构以每秒插入一百万个元素的速度运行两年才会出现溢出问题。

 


 

11.5 Sets and Bags

 

集合和包不同的地方在于,包的每个元素是可以多次出现的。

 

假设你想列出所有源代码中使用的标识符,并且过滤掉系统保留字。一些C 程序员会将这个保留字集合表示成字符数组,并搜索某个给定的单词是否在集合中。为了提高速度,他们甚至可能用二叉树来表达集合。

 

Lua 中,表达系统保留字这种集合的一个高效,简单的方法是将这些集合的元素作为表的索引。这样,用索引的方法就可以代替搜索操作,你只需要索引表并测试结果是不是nill

 

将集合的元素作为表的索引

 

reserved = {

       ["while"] = true, ["end"] = true,

       ["function"] = true, ["local"] = true,

}

for w in allwords() do

       if not reserved[w] then

              <do something with 'w'> -- 'w' is not a reserved word

       end

end

 

集合的创建

 

function Set (list)

       local set = {}

       for _, l in ipairs(list) do set[l] = true end

       return set

end

reserved = Set{"while", "end", "function", "local", }

 


 

Bags(包)也称为multisets(多重集合),不同于普通集合,多重集合的每个元素可以出现多次。

 

Lua 中表示包的方法和集合类似,只是每个索引都有与之对应的计数器。

 

包的创建

 

function insert (bag, element)

       bag[element] = (bag[element] or 0) + 1

end

 

function remove (bag, element)

       local count = bag[element]

       bag[element] = (count and count > 1) and count - 1 or nil

end

 

function Bag (list)

       local bag = {}

       for _, l in ipairs(list) do insert(bag, l) end

       return bag;

end

 

reserved = Bag{"while", "end", "function", "local", }

for i in pairs(reserved) do

       print(i, reserved[i])

end

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值