《Lua程序设计[第二版]》第11,12章笔记

来源:互联网 发布:数据的本质 电子书 编辑:程序博客网 时间:2024/06/05 05:22

第11章 数据结构

Lua中的table不是一种简单的数据结构,它可以作为其他数据结构的基础。通过table来表示数组、记录、线性表、队列、集合等。

 

11.1数组

使用整数来索引table即可在Lua中实现数组,一般以1作为数组起始索引。

a = {}

for i=1, 1000 do

a[i] = 0

end

print(#a)         –> 1000

 

11.2 矩阵与多维数组

两种方法表示矩阵。第一种是使用一个“数组的数组”,也就是说,一个table中的每个元素是另一个table。下面的代码创建了N X M的零矩阵:

mt = {}

for i=1, N do

mt[i] = {}

for j=1, M do

mt[i][j] = 0

end

end

第二个方法时将两个索引合并为一个索引。如果两个索引是整数,可以将第一个索引乘以一个适当的常量,并加上第二个索引。以下代码就是用这种方法来创建N X M的零矩阵:

mt = {}

for i = 1, N do

for j = 1, M do

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

end

end

 

11.3 链表

在Lua中实现链表,每个结点以一个table来表示,一个“链接”只是结点table中的一个字段,该字段包含了对其他table的引用。

list = nil

list = {next = list, value = v}

local l = list

while l do

print(l.value)

l = l.next

end

 

11.4 队列与双向队列

使用Lua的table库提供的insert和remove操作来实现队列,但这种方式实现的队列处理大数据量时效率太低。一种更高效的实现是使用两个索引,分别用于首尾的两个元素:

function ListNew ()return {first = 0, last = 1}endList = {}function List.new()return {first = 0, last = -1}endfunction List.pushfirst (list, value)local first = list.first - 1list.first = firstlist[first] = valueendfunction List.pushlast(list, value)local last = list.last + 1list.last = lastlist[last] = valueendfunction List.popfirst (list)local first = list.firstif first > list.last thenenderror ("list is empty")endlocal value = list[first]list[first] = nil  -- 为了允许垃圾收集list.first = first + 1return valueendfunction List.poplast (list)local last = list.lastif list.first > last thenerror("list is empty")endlocal value = list[last]list[last] = nil  -- 为了允许垃圾收集list.last = last - 1return valueend

11.5 集合与无序组(bag)

 

11.6 字符串缓冲

 

11.7 图

Lua允许程序员写出多种图的实现,每种实现都有其所适用的算法。这里要介绍一种简单的面向对象的实现,其中结点表示为对象,边表示为结点间的引用。

每一个结点表示为一个table,这个table有两个字段:name(结点的名称)和adj(于此结点邻接的结点集合)。下面是代码的实现:

-- 根据给定的名称返回对应的结点local function name2node (graph, name)if not graph[name] then -- 如果结点不存在graph[name] = {name = name, adj = {}}endreturn graph[name]end-- 构造图function readgraph ()local graph = {}for line in io.lines() do -- 切分行中的两个名称local namefrom, nameto = string.match(line, "(%s+)%s+(%s+)")local from = name2node(graph, nameto)-- 查找相应的结点from.adj[to] = true -- 将“to“添加到”from“的邻接集合endreturn graphend-- 函数findpath采用深度优先遍历算法,在两个结点间搜索一条路径-- 它的第一个参数是当前结点,第二个参数是目标节点,-- 第三个参数用于保存从起点到当前结点的路径,第四个参数是已访问结点的集合-- 【注意】该算法直接对结点进行操作,而不是它们的名称function findpath (curr, to, path, xisited)path = path or {}visited = visited or {}if visited[curr] then-- 结点是否已访问过?return nil -- 这里没有路径endvisited[curr] = true-- 将结点标记为已访问path[#path + 1] = curr-- 将其加到路径中if curr == to then -- 最后的结点吗?return pathendfor node in pairs(curr.adj) do -- 尝试所有的邻接结点local p = findpath(node, to, path, visited)if p thenreturn pendendpath[#path] = nil-- 从路径中删除节点end-- 测试上面所列函数function printpath(path)for i=1, #path doprint(path[i].name)endendg = readgraph()a = name2node(g, "a")b = name2node(g, "b")p = findpath(a,b)if p thenprintpath (p)end

 

第12章 数据文件与持久性

12.1 数据文件

 

12.2 串行化(Serialization)

通常需要串行化一些数据,也就是将数据转换为一个字节流或一个字符流。然后就可以将其存储到一个文件中,或者通过网络连接发送出去了。

Lua5.1提供了一种安全的方法来括住任意字符串的方法。标记方式为:[=[…]=],用于长字符串。

 

12.2.1 保存无环的table

 

12.2.2 保存有环的table

 

 

第13章 … 请看该系列的下一篇