《Lua程序设计第四版》 第二部分14~17章自做练习题答案 ...

打印 上一主题 下一主题

主题 896|帖子 896|积分 2688

Lua程序设计第四版第二部分编程实操自做练习题答案,带⭐为重点。
14.1 ⭐

该函数用于两个稀疏矩阵相加
  1. function martixAdd(a, b)
  2.     local c = {}
  3.     for i = 1, #a, 1 do
  4.         c[i] = {}
  5.         for k, v in pairs(a[i]) do
  6.             c[i][k] = v
  7.         end
  8.     end
  9.     for i = 1, #b, 1 do
  10.         for k, v in pairs(b[i]) do
  11.             c[i][k] = (c[i][k] or 0) + v
  12.             c[i][k] = (c[i][k] ~= 0) and c[i][k] or nil
  13.         end
  14.     end
  15.     return c
  16. end
  17. A = {{
  18.     [5] = 1
  19. }, {}, {
  20.     [1] = 3,
  21.     [3] = 4
  22. }, {}, {
  23.     [4] = -1
  24. }}
  25. B = {{
  26.     [2] = 2
  27. }, {}, {
  28.     [1] = -3,
  29.     [4] = -3
  30. }, {
  31.     [3] = 8
  32. }, {
  33.     [1] = 7
  34. }}
  35. for k, v in pairs(martixAdd(A, B)) do
  36.     for j, i in pairs(v) do
  37.         print(k .. "行", j .. "列", i)
  38.     end
  39. end
复制代码
14.2

改写队列的实现,使得当队列为空时两个索引都返回0
  1. function listNew()
  2.     return {
  3.         _first = 0,
  4.         _last = -1,
  5.         first = function()
  6.             if _first > _last then
  7.                 return 0
  8.             end
  9.             return _first
  10.         end,
  11.         last = function()
  12.             if _first > _last then
  13.                 return 0
  14.             end
  15.             return _last
  16.         end
  17.     }
  18. end
  19. l = listNew()
  20. -- 模拟空队列
  21. l._first = 10
  22. l._last = 9
  23. print(l.first, l.last)
复制代码
14.3

修改图所用的数据结构,使得图可以保存每条边的标签。该数据结构应该使用包括两个字段的对象来表示每一条边,即边的标签和边指向的节点。与邻接集合不同,每一个节点保存的是从当前节点出发的边的集合。
  1. local function name2node(graph, name)
  2.     local node = graph[name]
  3.     if not node then
  4.         graph[name] = {
  5.             name = name,
  6.             edges = {}
  7.         }
  8.         node = graph[name]
  9.     end
  10.     return node
  11. end
  12. function readgraph(file)
  13.     local graph = {}
  14.     f = io.open(file, 'r')
  15.     for l in f:lines() do
  16.         local name1, name2, edgeLabel = string.match(l, "(%S+)%s+(%S+)%s+(%S+)")
  17.         local from = name2node(graph, name1)
  18.         local to = name2node(graph, name2)
  19.         table.insert(from.edges, {
  20.             ["label"] = edgeLabel,
  21.             ["adj"] = to
  22.         })
  23.     end
  24.     return graph
  25. end
  26. graph = readgraph("graph.txt")
  27. for k, v in pairs(graph) do
  28.     for _, v in pairs(v.edges) do
  29.         print(k, v.label, v.adj.name)
  30.     end
  31. end
  32. [[
  33. C       1       D
  34. C       3       E
  35. D       1       C
  36. D       7       E
  37. A       4       B
  38. A       2       D
  39. B       1       D
  40. B       4       C
  41. ]]
复制代码
  1. A B 4
  2. A D 2
  3. B D 1
  4. D C 1
  5. C D 1
  6. B C 4
  7. D E 7
  8. C E 3
复制代码
14.4 ⭐

使用14.3的表示方式,其中边的标签代表两个终端节点之间的距离。该函数使用Dijkstra算法寻找两个指定节点之间的最短路径。
  1. local function name2node(graph, name)
  2.     local node = graph[name]
  3.     if not node then
  4.         graph[name] = {
  5.             name = name,
  6.             edges = {}
  7.         }
  8.         node = graph[name]
  9.     end
  10.     return node
  11. end
  12. function readgraph(file)
  13.     local graph = {}
  14.     f = io.open(file, 'r')
  15.     for l in f:lines() do
  16.         local name1, name2, edgeLabel = string.match(l, "(%S+)%s+(%S+)%s+(%S+)")
  17.         local from = name2node(graph, name1)
  18.         local to = name2node(graph, name2)
  19.         table.insert(from.edges, {
  20.             ["label"] = edgeLabel,
  21.             ["adj"] = to
  22.         })
  23.     end
  24.     return graph
  25. end
  26. graph = readgraph("graph.txt")
  27. for k, v in pairs(graph) do
  28.     for _, v in pairs(v.edges) do
  29.         print(k, v.label, v.adj.name)
  30.     end
  31. end
  32. function Dijkstra(graph, a, b)
  33.     -- 点不存在
  34.     if not graph[a] or not graph[b] then
  35.         return nil
  36.     end
  37.     local D = {}
  38.     local T = {}
  39.     -- D 加入起点
  40.     D[graph[a]] = 0
  41.     -- T 加入其他点,初始化可达最短距离为正无穷大
  42.     for name, node in pairs(graph) do
  43.         if name ~= a then
  44.             T[node] = math.maxinteger
  45.         end
  46.     end
  47.     -- 当D中不包含b点时循环
  48.     while not D[graph[b]] do
  49.         -- 根据 D 迭代 T 可达最短距离
  50.         for node, d in pairs(D) do
  51.             for _, edge in pairs(node.edges) do
  52.                 if not D[edge.adj] then
  53.                     local newD = d + tonumber(edge.label)
  54.                     T[edge.adj] = math.min(T[edge.adj], newD)
  55.                 end
  56.             end
  57.         end
  58.         -- 选择 T 可达距离最小的点
  59.         local tmp = nil
  60.         for node, d in pairs(T) do
  61.             tmp = tmp or node
  62.             if d < T[tmp] then
  63.                 tmp = node
  64.             end
  65.         end
  66.         -- 如果没有点被选中,退出循环
  67.         if T[tmp] == math.maxinteger then
  68.             return nil
  69.         end
  70.         -- 将前面选择到的点加入D,并从T删除
  71.         D[tmp] = T[tmp]
  72.         T[tmp] = nil
  73.     end
  74.     return D[graph[b]]
  75. end
  76. d = Dijkstra(graph, "A", "E")
  77. if not d then
  78.     print("无路径")
  79. end
  80. print(d)
  81. -- 具体路径计算为 A->E 路径距离 - (X->E 路径距离) == A -> X 路径距离
  82. -- 即 A->X->E
复制代码
15.1~15.2

修改序列化函数,使其带缩进地输出嵌套表,并添加["key"]=value的语法
  1. function serialize(o, tab)
  2.     tab = tab or 1
  3.     local t = type(o)
  4.     if t == "number" or t == "string" or t == "boolean" or t == "nil" then
  5.         io.write(string.format("%q", o))
  6.     elseif t == "table" then
  7.         io.write("{\n")
  8.         for k, v in pairs(o) do
  9.             io.write(string.rep("   ", tab))
  10.             io.write(" [", string.format("%s", serialize(k)), "] = ")
  11.             serialize(v, tab + 1)
  12.             io.write(",\n")
  13.         end
  14.         io.write(string.rep("   ", tab))
  15.         io.write("}")
  16.     else
  17.         error("cannot serialize a" .. t)
  18.     end
  19. end
  20. A = {
  21.     B = {
  22.         E = "dog",
  23.         H = {
  24.             F = "PIG",
  25.             G = "goose"
  26.         }
  27.     },
  28.     C = "apple",
  29.     D = 114514,
  30.     I = {1, 2, 3, {4, 5, 6}}
  31. }
  32. serialize(A)
  33. [[
  34. {
  35.     ["C"] = "apple",
  36.     ["D"] = 114514,
  37.     ["I"] = {
  38.        [1] = 1,
  39.        [2] = 2,
  40.        [3] = 3,
  41.        [4] = {
  42.           [1] = 4,
  43.           [2] = 5,
  44.           [3] = 6,
  45.          },
  46.       },
  47.     ["B"] = {
  48.        ["E"] = "dog",
  49.        ["H"] = {
  50.           ["G"] = "goose",
  51.           ["F"] = "PIG",
  52.          },
  53.       },
  54.    }
  55. ]]
复制代码
15.3

修改15.2,使其只在必要时,当键为字符串而不是合法标识符时才使用形如["key"]=value的语法
  1. function serialize(o, tab)
  2.     tab = tab or 1
  3.     local t = type(o)
  4.     if t == "number" or t == "string" or t == "boolean" or t == "nil" then
  5.         io.write(string.format("%q", o))
  6.     elseif t == "table" then
  7.         io.write("{\n")
  8.         for k, v in pairs(o) do
  9.             io.write(string.rep("   ", tab))
  10.             if type(k) == "string" and string.match(k, "[%a_]+[%w_]*") then
  11.                 io.write("  ", k, "  = ")
  12.             else
  13.                 io.write(" [")
  14.                 serialize(k)
  15.                 io.write("] = ")
  16.             end
  17.             serialize(v, tab + 1)
  18.             io.write(",\n")
  19.         end
  20.         io.write(string.rep("   ", tab))
  21.         io.write("}")
  22.     else
  23.         error("cannot serialize a" .. t)
  24.     end
  25. end
  26. A = {
  27.     B = {
  28.         E = "dog",
  29.         H = {
  30.             F = "PIG",
  31.             G = "goose"
  32.         }
  33.     },
  34.     C = "apple",
  35.     D = 114514,
  36.     I = {1, 2, 3, {4, 5, 6}}
  37. }
  38. serialize(A)
  39. [[
  40. {
  41.      C  = "apple",
  42.      D  = 114514,
  43.      I  = {
  44.        [1] = 1,
  45.        [2] = 2,
  46.        [3] = 3,
  47.        [4] = {
  48.           [1] = 4,
  49.           [2] = 5,
  50.           [3] = 6,
  51.          },
  52.       },
  53.      B  = {
  54.         E  = "dog",
  55.         H  = {
  56.            G  = "goose",
  57.            F  = "PIG",
  58.          },
  59.       },
  60.    }
  61. ]]
复制代码
15.4

使其在可能时使用列表的构造器语法。例如应将表{14,15,19}序列化为{14,15,19},而不是{[1] =14,[2]=15,[3]=19},在遍历该部分的时候不要重复序列化。
  1. function serialize(o)
  2.     local typ = type(o)
  3.     if typ == "number" or typ == "string" or typ == "boolean" or typ == "nil" then
  4.         io.write(string.format("%q", o))
  5.     elseif typ == "table" then
  6.         io.write("{\n")
  7.         local hash = {}
  8.         -- 遍历列表并进行hash记录
  9.         for i, v in ipairs(o) do
  10.             serialize(v)
  11.             io.write(",")
  12.             hash[i] = true
  13.         end
  14.         _ = (#hash ~= 0) and io.write("\n") or nil
  15.         -- 遍历除列表之外的所有元素
  16.         for k, v in pairs(o) do
  17.             if type(k) == "string" and string.match(k, "[%a_]+[%w_]*") then
  18.                 io.write(" ", k, " = ")
  19.             elseif hash[k] == true then
  20.                 goto continue
  21.                 -- do nothing
  22.             else
  23.                 io.write(" [")
  24.                 serialize(k)
  25.                 io.write("] = ")
  26.             end
  27.             serialize(v)
  28.             io.write(",\n")
  29.             ::continue::
  30.         end
  31.         io.write("}")
  32.     else
  33.         error("cannot serialize a" .. t)
  34.     end
  35. end
  36. A = {
  37.     B = {
  38.         E = "dog",
  39.         H = {
  40.             F = "PIG",
  41.             G = "goose"
  42.         }
  43.     },
  44.     C = "apple",
  45.     D = 114514,
  46.     I = {1, 2, 3, {4, 5, 6}},
  47.     [1] = 4,
  48.     [2] = 3,
  49.     [3] = 3,
  50.     [5] = 4
  51. }
  52. serialize(A)
  53. TEST = {
  54.     4,
  55.     3,
  56.     3,
  57.     [5] = 4,
  58.     C = "apple",
  59.     D = 114514,
  60.     I = {1, 2, 3, {4, 5, 6}},
  61.     B = {
  62.         E = "dog",
  63.         H = {
  64.             G = "goose",
  65.             F = "PIG"
  66.         }
  67.     }
  68. }
  69. [[
  70. {
  71. 4,3,3,
  72. [5] = 4,
  73. C = "apple",
  74. D = 114514,
  75. I = {
  76. 1,2,3,{
  77. 4,5,6,
  78. },
  79. },
  80. B = {
  81. E = "dog",
  82. H = {
  83. G = "goose",
  84. F = "PIG",
  85. },
  86. },
  87. }
  88. ]]
复制代码
16.1

通常,在加载代码段时增加一些前缀很有用。该函数类似于函数load,不过会将第一个参数增加到待加载的代码段之前。
像原始的load函数一样,函数loadwithprefix应该既可以接收字符串形式的代码段,也可以通过函数进行读取。即使待加载的代码段是字符串形式的,函数loadwithprefix也不应该进行实际的字符串连接操作。相反,它应该调用函数load并传入一个恰当的读取函数来实现功能,这个读取函数首先返回要增加的代码,然后返回原始的代码段。
  1. function loadWithPrefix(s, f)
  2.     local tmp = 1
  3.     return load(function()
  4.         if tmp == 1 then
  5.             tmp = 2
  6.             return s
  7.         elseif tmp == 2 then
  8.             if type(f) == "string" then
  9.                 tmp = 3
  10.                 return f
  11.             elseif type(f) == "function" then
  12.                 return f()
  13.             end
  14.         else
  15.             return nil
  16.         end
  17.     end)
  18. end
  19. f = loadWithPrefix("local x = 100;", "print(x)")
  20. f()
  21. f = loadWithPrefix("local x = 100;", io.lines('load.txt', '*L'))
  22. f()
复制代码
16.2 ⭐

请编写一个函数mulitiload,该函数接收一组字符串或函数来生成函数。其他规则与16.1类似。
[code]function multiLoad(...)    local t = {...}    local i = 1    return load(function()        ::continue::        if i

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表