Lua教程(七):数据结构详解

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

1. 数组:

使用整数来索引table即可在Lua中实现数组。因此,Lua中的数组没有固定的大小,如:

代码如下:

a = {}
 for i = 1, 1000 do
     a[i] = 0
 end
 print("The length of array 'a' is " .. #a)
 --The length of array 'a' is 1000

在Lua中,可以让任何数作为数组的起始索引,但通常而言,都会使用1作为其起始索引值。而且很多Lua的内置功能和函数都依赖这一特征,因此在没有充分理由的前提下,尽量保证这一规则。下面的方法是通过table的构造器来创建并初始化一个数组的,如:
 

代码如下:

squares = {1, 4, 9, 16, 25}

 2. 二维数组:

在Lua中我们可以通过两种方式来利用table构造多维数组。其中,第一种方式通过“数组的数组”的方式来实现多维数组的,即在一维数组上的每个元素也同样为table对象,如:

代码如下:

mt = {}
for i = 1, N do
    mt[i] = {}
    for j = 1, M do
        mt[i][j] = i * j
    end
end

第二种方式是将二维数组的索引展开,并以固定的常量作为第二维度的步长,如:

代码如下:

mt = {}
 for i = 1, N do
     for j = 1, M do
         mt[(i - 1) * M + j] = i * j
     end
 end

3. 链表:

由于table是动态的实体,所以在Lua中实现链表是很方便的。其中,每个结点均以table来表示,一个“链接”只是结点中的一个字段,该字段包含对其它table的引用,如:

代码如下:

list = nil
for i = 1, 10 do
    list = { next = list, value = i}
end

local l = list
while l do
    print(l.value)
    l = l.next
end

 4. 队列与双向队列:

在Lua中实现队列的简单方法是使用table库函数insert和remove。但是由于这种方法会导致后续元素的移动,因此当队列的数据量较大时,不建议使用该方法。下面的代码是一种更高效的实现方式,如:

代码如下:

List = {}

function List.new()
    return {first = 0, last = -1}
end

function List.pushFront(list, value)
    local first = list.first - 1
    list.first = first
    list[first] = value
end

function List.pushBack(list, value)
    local last = list.last + 1
    list.last = last
    list[last] = value
end

function List.popFront(list)
    local first = list.first
    if first > list.last then
        error("List is empty")
    end
    local value = list[first]
    list[first] = nil
    list.first = first + 1
    return value
end

function List.popBack(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

  5. 集合和包(Bag):

在Lua中用table实现集合是非常简单的,见如下代码:
 

代码如下:

reserved = { ["while"] = true, ["end"] = true, ["function"] = true, }
    if not reserved["while"] then
        --do something
    end

在Lua中我们可以将包(Bag)看成MultiSet,与普通集合不同的是该容器中允许key相同的元素在容器中多次出现。下面的代码通过为table中的元素添加计数器的方式来模拟实现该数据结构,如:

代码如下:

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

 6. StringBuilder:
    如果想在Lua中将多个字符串连接成为一个大字符串的话,可以通过如下方式实现,如:

代码如下:

local buff = ""
 for line in io.lines() do
     buff = buff .. line .. "\n"
 end

上面的代码确实可以正常的完成工作,然而当行数较多时,这种方法将会导致大量的内存重新分配和内存间的数据拷贝,由此而带来的性能开销也是相当可观的。事实上,在很多编程语言中String都是不可变对象,如Java,因此如果通过该方式多次连接较大字符串时,均会导致同样的性能问题。为了解决该问题,Java中提供了StringBuilder类,而Lua中则可以利用table的concat方法来解决这一问题,见如下代码:

代码如下:

local t = {}
for line in io.lines() do
    t[#t + 1] = line .. "\n"
end
local s = table.concat(t)

--concat方法可以接受两个参数,因此上面的方式还可以改为:
local t = {}
for line in io.lines() do
    t[#t + 1] = line
end
local s = table.concat(t,"\n")

(0)

相关推荐

  • Lua教程(二):基础知识、类型与值介绍

    一.基础知识: 1. 第一个程序和函数:     在目前这个学习阶段,运行Lua程序最好的方式就是通过Lua自带的解释器程序,如:   复制代码 代码如下: /> lua     > print("Hello World")     Hello World 这样我们就可以以交互性的方式输入lua代码,并立即得到执行结果了.对于代码块较少的测试程序来说,这种方式确实是非常方便的,然而对于相对复杂的程序而言,这种方式就不是很合适了.如果是这样,我们可以将Lua代码保存到一个独立

  • Lua教程(五):迭代器和泛型for

    1. 迭代器与Closure: 在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的"下一个"元素.每个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置和下一次遍历时的位置.从这一点看,Lua中closure机制为此问题提供了语言上的保障,见如下示例: 复制代码 代码如下: function values(t)     local i = 0     return function()         i = i + 1         return t[i

  • Lua教程(三):表达式和语句

    一.表达式: 1. 算术操作符:     Lua支持常规算术操作符有:二元的"+"."-"."*"."/"."^"(指数)."%"(取模),一元的"-"(负号).所有这些操作符都可用于实数.然而需要特别说明的是取模操作符(%),Lua中对该操作符的定义为:   复制代码 代码如下: a % b == a - floor(a / b) * b 由此可以推演出x % 1的

  • Lua教程(一):简介、优势和应用场景介绍

    一.简介: Lua作为目前最为流行的.免费轻量级嵌入式脚本语言,在很多工业级的应用程序中被广泛应用,如Adobe's Photoshop,甚至是在一些著名的游戏程序中也被大量使用,如星际.不仅如此,由于Lua具备很多特殊的优点,如语法简单(基于过程).高效稳定(基于字节码).可以处理复杂的数据结构.动态类型.以及自动内存管理(基于垃圾收集)等,因此在很多嵌入式设备和智能移动设备中,为了提高程序的灵活性.扩展性和高可配置性,一般都会选择Lua作为它们的脚本引擎,以应对各种因设备不同而带来的差异.

  • Lua教程(六):编译执行与错误

    1. 编译:     Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块.但实际上dofile只是一个辅助函数,loadfile才是真正的核心函数.相比于dofile,loadfile只是从指定的文件中加载Lua代码块,然后编译这段代码块,如果有编译错误,就返回nil,同时给出错误信息,但是在编译成功后并不真正的执行这段代码块.因此,我们可以将dofile实现为: 复制代码 代码如下: function dofile(filename)      local f = ass

  • Lua教程(四):函数详解

    一.函数: 在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y).唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量或table的构造器,那么圆括号可以省略,如print "Hello World"和f {x = 20, y = 20}.     Lua为面对对象式的调用也提供了一种特殊的语法--冒号操作符.表达式o.foo(o,x)的另一种写法是o:foo(x).冒号操作符使调用o.foo

  • Python运算符教程之逻辑门详解

    目录 1. 与门 2. 与非门 3. 或门 4. 异或 5. NOT Gate 6. NOR 门 7. XNOR 门 逻辑门是任何数字电路的基本构建块.它需要一两个输入并根据这些输入产生输出.输出可能为高 (1) 或低 (0).逻辑门使用二极管或晶体管实现.它也可以使用真空管.光学元件.分子等电磁元件构成.在计算机中,大多数电子电路都是由逻辑门组成的.逻辑门用于执行计算.数据存储或展示面向对象编程(尤其是继承的力量)的电路. 定义了七个基本逻辑门:与门.或门.非门.与非门.或非门.异或门.异或门

  • es6系列教程_ Map详解以及常用api介绍

    ECMAScript 6中的Map类型是一种存储着许多键值对的有序列表.键值对支持所有的数据类型. 键 0 和 '0'会被当做两个不同的键,不会发生强制类型转换. 如何使用Map? let map = new Map(); 常用方法: set( 键,值 ): 添加新的键值对元素 get( 键 ): 获取键对应的值,如果这个值不存在,返回undefined let map = new Map(); map.set( '0', 'ghostwu' ); map.set( 0, 'ghostwu' )

  • Kerberos安装教程及使用详解

    Kerberos协议: Kerberos协议主要用于计算机网络的身份鉴别(Authentication), 其特点是用户只需输入一次身份验证信息就可以凭借此验证获得的票据(ticket-granting ticket)访问多个服务,即SSO(Single Sign On).由于在每个Client和Service之间建立了共享密钥,使得该协议具有相当的安全性. 2. 安装 Kerberos 2.1. 环境配置 安装kerberos前,要确保主机名可以被解析. 主机名 内网IP 角色 Vmw201

  • vue中datepicker的使用教程实例代码详解

    写这个文章主要是记录下用法,官网已经说的很详细了 npm install vue-datepicker --save html代码 <myDatepicker :date="startTime" :option="multiOption" :limit="limit"></myDatepicker> <myDatepicker :date="endtime" :option="timeo

  • C++与Lua交互原理实例详解

    首先,不同语言交互,我们一般把这种编程方式称为混合编程.开发中为什么要多语言混合使用,只用c++不行吗?答案是因为脚本语言语法糖多使用方便.沙盒式安全机制使系统更稳定.简单易学降低开发成本等,那么,只用脚本不行吗?那也是不合理的,因为与系统api的接口.计算密集性模块的性能要求等是脚本语言不擅长的,这一部份仍然需要c/c++来完成.因此,为了综合各自的优势,就出现了混合编程的需要. 那么,在一个程序的生命周期里,具体哪些部份c++写,哪些部份是脚本写?它们的交互接口又在哪里?一般与系统紧密相关的

  • Python基础之数据结构详解

    一.列表 创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来 示例: list01 = ['a','b','c'] 1.1 列表更新元素 一个列表是可以储存不同的类型的数据结构,并且修改的新元素也不一定需要和原来的元素类型一致,但是要注意的是,更新列表的索引必须是已存在的索引,不能对超出列表的索引更新元素 1.2 列表增加元素 增加元素的方法: 1.append方法:在列表的最后增加一个元素. list01 = ['a', 'b', 'c'] list01 .append('d') pr

  • java实现队列queue数据结构详解

    目录 概念 队列中两个主要操作 队列遵循以下条件: 队列的数组实现 总结 概念 队列是一种非原始(特殊)的线性表,是一种先进先出(FIFO)的数据结构.它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作. FIFO:first input first output,即先添加的元素,先移除,最后添加的元素,最后移除. 工作方式类似于商场排队结账情形: 数组模拟队列图示: 队列中两个主要操作 插入值操作:insert ——> enqueue(入队) ——>参数是要插

  • Python Pandas学习之Pandas数据结构详解

    目录 1Pandas介绍 2Pandas数据结构 2.1Series 2.2DataFrame 1 Pandas介绍 2008年WesMcKinney开发出的库 专门用于数据挖掘的开源python库 以Numpy为基础,借力Numpy模块在计算方面性能高的优势 基于matplotlib,能够简便的画图 独特的数据结构 Numpy已经能够帮助我们处理数据,能够结合matplotlib解决部分数据展示等问题,那么pandas学习的目的在什么地方呢? 增强图表可读性 便捷的数据处理能力 读取文件方便

  • Python Pandas 中的数据结构详解

    目录 1.Series 1.1通过列表创建Series 1.2通过字典创建Series 2.DataFrame 3.索引对象 4.查看DataFrame的常用属性 前言: Pandas有三种数据结构:Series.DataFrame和Panel.Series类似于数组:DataFrame类似于表格:Panel可视为Excel的多表单Sheet 1.Series Series是一种一维数组对象,包含一个值序列,并且包含数据标签,称为索引(index),通过索引来访问数组中的数据. 1.1通过列表创

  • Redis 哈希Hash底层数据结构详解

    目录 1. Redis 底层数据结构 2. hashtable 3. redisDb 与 redisObject 4. ziplist 5. linkedlist 6. quicklist 1. Redis 底层数据结构 Redis数据库就像是一个哈希表,首先对key进行哈希运算得到哈希值再取模得到一个下标,每个元素是一个节点,节点之间形成链表.这感觉有点像Java中的HashMap. 不同的数据类型的实现方式是不一样的,可以通过object encoding命令查看底层真正的数据存储结构 同一

随机推荐