第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} 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 enderror ("list is empty") end local value = list[first] list[first] = nil -- 为了允许垃圾收集 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 -- 为了允许垃圾收集 list.last = last - 1 return value end
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 = {}} end return 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“的邻接集合 end return graph end -- 函数findpath采用深度优先遍历算法,在两个结点间搜索一条路径 -- 它的第一个参数是当前结点,第二个参数是目标节点, -- 第三个参数用于保存从起点到当前结点的路径,第四个参数是已访问结点的集合 -- 【注意】该算法直接对结点进行操作,而不是它们的名称 function findpath (curr, to, path, xisited) path = path or {} visited = visited or {} if visited[curr] then -- 结点是否已访问过? return nil -- 这里没有路径 end visited[curr] = true -- 将结点标记为已访问 path[#path + 1] = curr -- 将其加到路径中 if curr == to then -- 最后的结点吗? return path end for node in pairs(curr.adj) do -- 尝试所有的邻接结点 local p = findpath(node, to, path, visited) if p then return p end end path[#path] = nil -- 从路径中删除节点 end -- 测试上面所列函数 function printpath(path) for i=1, #path do print(path[i].name) end end g = readgraph() a = name2node(g, "a") b = name2node(g, "b") p = findpath(a,b) if p then printpath (p) end
第12章 数据文件与持久性
12.1 数据文件
略
12.2 串行化(Serialization)
通常需要串行化一些数据,也就是将数据转换为一个字节流或一个字符流。然后就可以将其存储到一个文件中,或者通过网络连接发送出去了。
Lua5.1提供了一种安全的方法来括住任意字符串的方法。标记方式为:[=[…]=],用于长字符串。
12.2.1 保存无环的table
略
12.2.2 保存有环的table
略
第13章 … 请看该系列的下一篇