008 数组队列(lua)

文章目录

  • 初步
    • array.lua
    • arrayqueue.lua
  • 修改(封装)
    • array.lua
    • arrayqueue.lua
    • 测试(直接在 arrayqueue.lua 文件的末尾添加)
  • 修改(本身就是动态扩容)
    • array.lua
    • arrayqueue.lua
  • 循环队列
    • LoopQueue.lua

初步

array.lua

Java是一种静态类型、面向对象的编程语言,而Lua是一种动态类型、脚本语言。在Lua中,没有类(class)的概念,但有表(table)来模拟对象的行为和存储数据。


-- array.lua  
local Array = {}  
Array.__index = Array  
  
function Array.new(capacity)  
    capacity = capacity or 10  
    local self = setmetatable({  
        data = {},  
        size = 0,  
        capacity = capacity  
    }, Array)  
    return self  
end  
  
function Array:addLast(e)  
    if #self.data >= self.capacity then  
        self:resize(2 * self.capacity)  
    end  
    self.data[self.size + 1] = e  
    self.size = self.size + 1  
end  
  
function Array:removeFirst()  
    if self:isEmpty() then  
        error("Attempt to remove from an empty array")  
    end  
    local first = self.data[1]  
    for i = 1, self.size - 1 do  
        self.data[i] = self.data[i + 1]  
    end  
    self.data[self.size] = nil  
    self.size = self.size - 1  
    if self.size == self.capacity / 4 and self.capacity / 2 ~= 0 then  
        self:resize(self.capacity / 2)  
    end  
    return first  
end  
  
function Array:getFirst()  
    if self:isEmpty() then  
        error("Attempt to get first element from an empty array")  
    end  
    return self.data[1]  
end  
  
function Array:getSize()  
    return self.size  
end  
  
function Array:isEmpty()  
    return self.size == 0  
end  
  
function Array:resize(newCapacity)  
    local newData = {}  
    for i = 1, self.size do  
        newData[i] = self.data[i]  
    end  
    self.data = newData  
    self.capacity = newCapacity  
end  
  
-- 可能还需要添加其他方法,如addFirst, get等  
  
return Array


arrayqueue.lua

接下来,我们使用array.lua模块来定义ArrayQueue。


-- arrayqueue.lua  
local Array = require("array")  -- 假设array.lua在同一目录下  
  
ArrayQueue = {}  
ArrayQueue.__index = ArrayQueue  
  
function ArrayQueue.new(capacity)  
    local self = setmetatable({  
        array = Array.new(capacity)  
    }, ArrayQueue)  
    return self  
end  
  
function ArrayQueue:enqueue(e)  
    self.array:addLast(e)  
end  
  
function ArrayQueue:dequeue()  
    return self.array:removeFirst()  
end  
  
function ArrayQueue:getFront()  
    return self.array:getFirst()  
end  
  
function ArrayQueue:isEmpty()  
    return self.array:isEmpty()  
end  
  
function ArrayQueue:getSize()  
    return self.array:getSize()  
end  
  
function ArrayQueue:toString()  
    local res = "Queue: front ["  
    for i = 1, self.array:getSize() do  
        res = res .. tostring(self.array.data[i])  
        if i ~= self.array:getSize() then  
            res = res .. ", "  
        end  
    end  
    res = res .. "] tail"  
    return res  
end  
  
-- 测试代码  
local queue = ArrayQueue.new()  
for i = 1, 9 do  
    queue:enqueue(i)  
    print(queue:toString())  
    if i % 3 == 2 then  
        queue:dequeue()  
        print(queue:toString())  
    end  
end


Lua脚本中的Array和ArrayQueue都使用表(table)和元表(metatable)来模拟对象和方法。
Lua中数组索引默认从1开始,而Java从0开始。
Lua没有静态类型检查,所以在运行时需要更仔细地处理错误和异常情况。
Lua脚本中的模块(如array.lua)用于封装和重用代码。
Lua的require函数用于加载和执行Lua文件。这里假设array.lua和arrayqueue.lua在同一目录下。

在 ArrayQueue:toString() 方法中直接访问 self.array.data 并不是最佳实践,因为这破坏了封装性。Array 类应该负责其内部数据的所有操作,包括如何遍历和展示这些数据。

修改(封装)

array.lua


local Array = {}  
Array.__index = Array  
  
function Array.new(capacity)  
    capacity = capacity or 10  
    local self = setmetatable({  
        data = {},  
        size = 0,  
        capacity = capacity  
    }, Array)  
    return self  
end  
  
function Array:addLast(e)  
    if self.size >= self.capacity then  
        self:resize(2 * self.capacity)  
    end  
    self.data[self.size + 1] = e  
    self.size = self.size + 1  
end  
  
function Array:removeFirst()  
    if self:isEmpty() then  
        error("Attempt to remove from an empty array")  
    end  
    local first = self.data[1]  
    for i = 1, self.size - 1 do  
        self.data[i] = self.data[i + 1]  
    end  
    self.data[self.size] = nil  
    self.size = self.size - 1  
    if self.size == self.capacity / 4 and self.capacity / 2 ~= 0 then  
        self:resize(self.capacity / 2)  
    end  
    return first  
end  
  
function Array:getFirst()  
    if self:isEmpty() then  
        error("Attempt to get first element from an empty array")  
    end  
    return self.data[1]  
end  
  
function Array:getSize()  
    return self.size  
end  
  
function Array:isEmpty()  
    return self.size == 0  
end  
  
function Array:resize(newCapacity)  
    local newData = {}  
    for i = 1, self.size do  
        newData[i] = self.data[i]  
    end  
    self.data = newData  
    self.capacity = newCapacity  
end  
  
function Array:toString()  
    local res = "Array: ["  
    for i = 1, self.size do  
        res = res .. tostring(self.data[i])  
        if i ~= self.size then  
            res = res .. ", "  
        end  
    end  
    res = res .. "]"  
    return res  
end  
  
return Array

arrayqueue.lua


local Array = require("array")  
  
ArrayQueue = {}  
ArrayQueue.__index = ArrayQueue  
  
function ArrayQueue.new(capacity)  
    local self = setmetatable({  
        array = Array.new(capacity)  
    }, ArrayQueue)  
    return self  
end  
  
function ArrayQueue:enqueue(e)  
    self.array:addLast(e)  
end  
  
function ArrayQueue:dequeue()  
    return self.array:removeFirst()  
end  
  
function ArrayQueue:getFront()  
    return self.array:getFirst()  
end  
  
function ArrayQueue:isEmpty()  
    return self.array:isEmpty()  
end  
  
function ArrayQueue:getSize()  
    return self.array:getSize()  
end  
  
function ArrayQueue:toString()  
    local res = "Queue: front [" .. self.array:toString() .. "] tail"  
    return res  
end  
  
return ArrayQueue

测试(直接在 arrayqueue.lua 文件的末尾添加)


-- 测试代码  
local queue = ArrayQueue.new()  
for i = 1, 9 do  -- 注意这里从 1 开始迭代  
    queue:enqueue(i)  
    print(queue:toString())  
    if i % 3 == 0 then  -- 注意条件也做了相应调整  
        queue:dequeue()  
        print(queue:toString())  
    end  
end

修改(本身就是动态扩容)

在Lua中,数组(实际上是表)本身就是动态扩容的,不需要像Java那样手动管理容量和进行resize操作。
可以省略与容量管理相关的所有方法。

注意,Lua脚本中的“Array”将不再需要容量管理,而ArrayQueue将直接使用这个简化的“Array”。

array.lua


-- array.lua  
local Array = {}  
Array.__index = Array  
  
function Array.new()  
    local self = setmetatable({  
        data = {}  
    }, Array)  
    return self  
end  
  
function Array:addLast(e)  
    table.insert(self.data, e)  
end  
  
function Array:removeFirst()  
    if #self.data == 0 then  
        error("Attempt to remove from an empty array")  
    end  
    return table.remove(self.data, 1)  
end  
  
function Array:getFirst()  
    if #self.data == 0 then  
        error("Attempt to get first element from an empty array")  
    end  
    return self.data[1]  
end  
  
function Array:getSize()  
    return #self.data  
end  
  
function Array:isEmpty()  
    return #self.data == 0  
end  
  
function Array:toString()  
    local res = "Array: ["  
    for i, v in ipairs(self.data) do  
        res = res .. tostring(v)  
        if i ~= #self.data then  
            res = res .. ", "  
        end  
    end  
    res = res .. "]"  
    return res  
end  
  
return Array

arrayqueue.lua


-- arrayqueue.lua  
local Array = require("array")  
  
ArrayQueue = {}  
ArrayQueue.__index = ArrayQueue  
  
function ArrayQueue.new()  
    local self = setmetatable({  
        array = Array.new()  
    }, ArrayQueue)  
    return self  
end  
  
function ArrayQueue:enqueue(e)  
    self.array:addLast(e)  
end  
  
function ArrayQueue:dequeue()  
    return self.array:removeFirst()  
end  
  
function ArrayQueue:getFront()  
    return self.array:getFirst()  
end  
  
function ArrayQueue:isEmpty()  
    return self.array:isEmpty()  
end  
  
function ArrayQueue:getSize()  
    return self.array:getSize()  
end  
  
function ArrayQueue:toString()  
    local res = "Queue: front [" .. self.array:toString() .. "] tail"  
    return res  
end  
  
-- 测试代码  
local queue = ArrayQueue.new()  
for i = 1, 10 do  
    queue:enqueue(i)  
    print(queue:toString())  
    if i % 3 == 0 then  
        queue:dequeue()  
        print(queue:toString())  
    end  
end

在这个Lua脚本中,Array类现在只负责管理一个Lua表,并使用Lua内建的table.insert和table.remove方法来添加和删除元素。ArrayQueue类则使用这个简化的Array类来模拟队列的行为。测试代码部分展示了如何使用这个队列,包括入队、出队和打印队列状态。

dequeue() 方法的复杂度实际上是 O(n),尽管它看起来像是直接操作数组(在Lua中是表)的第一个元素。然而,这里的关键是Lua表并不总是以数组的形式存储数据,特别是在涉及到删除表的前端元素时。

在Lua中,表是通过哈希表实现的,这意味着它们可以非常高效地通过键来访问元素(对于整数键,Lua内部可能会使用一种类似于数组的结构来优化访问,但这取决于Lua引擎的具体实现和表的使用方式)。然而,当从表的前端删除元素时(即删除键为1的元素),Lua表不会自动地“压缩”或重新索引剩余的元素以填补被删除元素留下的空白。相反,它会留下这个空白,并简单地更新表的大小(即#table操作的结果)。

因此,从性能的角度来看,虽然删除操作本身可能是O(1)的(即直接设置table[1] = nil并将表的内部大小标记减1),但如果你之后想要迭代这个表并期望它按照索引顺序来迭代(比如使用ipairs),那么实际上你会遇到一个“空洞”,因为ipairs会从1开始迭代,直到遇到第一个不是整数的键或nil值为止。在这种情况下,虽然删除操作本身是快速的,但表现在逻辑上不再是一个紧凑的数组,这可能会影响后续操作的性能,特别是那些依赖于索引连续性的操作。

然而,如果你只关心删除操作的直接成本,并且不担心表内部结构的变化对后续操作的影响,那么可以说删除操作(在这个上下文中是dequeue()方法)是O(1)的。但在实际应用中,通常需要考虑这些后续影响,因此从更广泛的角度来看,将其视为O(n)(其中n是表中剩余元素的数量,考虑到后续可能需要重新组织或处理表)可能更为准确。

但请注意,这里的“O(n)”并不是指删除操作本身需要遍历整个表;而是指删除操作可能间接导致后续操作(如迭代)需要更多的工作来“跳过”表中的空洞。如果表的使用方式不涉及对空洞的敏感性(比如总是通过键直接访问元素),那么这种影响可能就不那么重要了。

另外,值得注意的是,Lua 5.3及更高版本引入了对表压缩的支持(通过table.pack和table.unpack函数,尽管它们与ipairs和直接操作表的方式不完全相同),但标准的表操作(如添加和删除元素)并不自动压缩表。如果你需要一个紧凑的数组结构,你可能需要自己实现这种压缩逻辑。

在Lua中,当你从表中删除第一个元素(即设置table[1] = nil),表并不会自动地重新组织,使得后面的元素都往前挪动来填补这个空白。Lua的表是基于哈希表的实现,它并不保证元素的物理顺序与插入顺序一致,除非这些元素都是使用连续的整数键插入的,并且没有使用过非整数键或删除了中间的元素。

即使所有的元素都是用连续的整数键插入的,Lua也不会在删除第一个元素后自动调整后续元素的键。相反,它会留下一个“空洞”,即键1对应的值为nil,而表的长度(通过#table获得的)会相应减少,但表的实际内存占用可能并不会立即减少,因为Lua的垃圾收集器会负责回收不再使用的内存空间。

因此,从这个角度来看,删除第一个元素的操作本身是O(1)的,因为它只需要设置一个键的值为nil并更新表的长度(尽管这个长度更新对于Lua用户来说可能是不可见的,因为它通常是通过#table这样的操作间接感知的)。但是,如果你之后需要以某种方式迭代这个表,并且你希望忽略掉这些空洞,那么你可能需要使用一种能够跳过nil值的迭代方法,比如编写自己的迭代函数,或者使用pairs而不是ipairs(但请注意pairs的迭代顺序是不确定的)。

然而,如果你确实需要一个在删除元素后能够自动重新组织,使得所有剩余元素都保持连续索引的数组结构,那么Lua标准库并不直接提供这样的功能。你需要自己实现这样的逻辑,比如在删除元素后遍历表,将所有后续元素都向前移动一位。这样的操作将是O(n)的,其中n是表中剩余元素的数量。

总结来说,Lua表在删除第一个元素时不会自动重新组织,删除操作本身是O(1)的,但后续操作(如迭代)可能会受到表中空洞的影响,而如果你需要保持元素的连续索引,则可能需要手动实现O(n)的重新组织逻辑。

循环队列

我们需要注意Lua与Java在数组(或表)处理、类型系统和内存管理方面的差异。Lua表是动态数组和哈希表的混合体,它们会自动扩容,但在这里我们将模拟Java中的固定容量数组行为,并通过手动调整front和tail指针来实现循环队列。

LoopQueue.lua


-- LoopQueue.lua  
  
local LoopQueue = {}  
LoopQueue.__index = LoopQueue  
  
function LoopQueue.new(capacity)  
    capacity = capacity or 10  
    local self = setmetatable({  
        data = {},  
        front = 1,  
        tail = 1,  
        size = 0,  
        capacity = capacity  
    }, LoopQueue)  
  
    -- 初始化data表,预留capacity+1个空间(Lua索引从1开始)  
    for _ = 1, capacity + 1 do  
        table.insert(self.data, nil)  
    end  
    return self  
end  
  
function LoopQueue:isEmpty()  
    return self.size == 0  
end  
  
function LoopQueue:getSize()  
    return self.size  
end  
  
function LoopQueue:getCapacity()  
    return self.capacity  
end  
  
function LoopQueue:enqueue(e)  
    if (self.tail + 1) % (self.capacity + 1) == self.front then  
        error("Queue is full")  
    end  
    self.data[self.tail] = e  
    self.tail = (self.tail + 1) % (self.capacity + 1)  
    self.size = self.size + 1  
end  
  
function LoopQueue:dequeue()  
    if self:isEmpty() then  
        error("Cannot dequeue from an empty queue.")  
    end  
    local ret = self.data[self.front]  
    self.data[self.front] = nil -- Lua中的nil相当于Java中的null,用于标记空位  
    self.front = (self.front + 1) % (self.capacity + 1)  
    self.size = self.size - 1  
    return ret  
end  
  
function LoopQueue:getFront()  
    if self:isEmpty() then  
        error("Queue is empty.")  
    end  
    return self.data[self.front]  
end  
  
function LoopQueue:toString()  
    local res = "Queue: size = " .. self.size .. ", capacity = " .. self.capacity .. "\n"  
    res = res .. "front ["  
    local i = self.front  
    while i ~= self.tail do  
        res = res .. tostring(self.data[i])  
        i = (i + 1) % (self.capacity + 1)  
        if i ~= self.tail then  
            res = res .. ", "  
        end  
    end  
    res = res .. "] tail"  
    return res  
end  
  
-- 测试代码  
local queue = LoopQueue.new()  
for i = 0, 9 do -- Lua中的for循环与Java类似(不过Lua索引从1开始)  
    queue:enqueue(i + 1) -- 我们需要显式地加1来匹配索引  
    print(queue:toString())  
  
    if (i + 1) % 3 == 0 then -- 同样地,我们需要对i+1取模,因为i是从0开始的  
        queue:dequeue()  
        print(queue:toString())  
    end  
end


Lua中的表索引默认从1开始,但在这个实现中,我们仍然模拟了Java中从0开始的“逻辑索引”(尽管在enqueue和dequeue操作中我们使用了从1开始的物理索引)。
Lua没有像Java那样的泛型类型,所以我们使用Lua的动态类型系统。
Lua表是动态扩容的,但在这个实现中,我们手动管理了容量(通过capacity字段),并在达到容量限制时抛出了错误。在Lua中,通常不需要这样做,因为表的自动扩容特性可以处理大多数情况。
Lua中的错误处理是通过error函数实现的,它会中断当前的执行流,并抛出一个错误。这与Java中的异常处理不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/769215.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ODN网络弱光聚类定界与整治

01 ODN网络弱光运维现状 ODN网络是家庭宽带连接系统-无源光网络 (PON) 的重要组成部分,是连接局端 OLT 和用户 ONT 之间的光路通道,其质量直接影响整个PON系统的性能及可靠性。ODN光纤链路包括OLT PON口、ODF、主干光纤、一级分光器、分支光纤、二级分光…

登录功能和校验

基础版 controller package com.web.management.controller;import com.web.management.pojo.Emp; import com.web.management.pojo.Result; import com.web.management.service.EmpService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.anno…

如何用Vue3和Plotly.js绘制交互式漏斗图

本文由ScriptEcho平台提供技术支持 项目地址:传送门 Plotly.js 绘制漏斗图 应用场景 漏斗图常用于可视化业务流程中的各个阶段的转换率,例如销售漏斗或营销漏斗。它可以帮助用户识别流程中的瓶颈和改进机会。 基本功能 本代码使用 Plotly.js 库绘制…

【微机原理及接口技术】中断控制器8259A

【微机原理及接口技术】中断控制器8259A 文章目录 【微机原理及接口技术】中断控制器8259A前言一、介绍二、8259A的内部结构和引脚三、8259A的中断工作过程四、8259A的工作方式五、8259A的编程六、外部中断服务程序总结 前言 本篇文章将就8259芯片展开介绍,8259A的…

【多媒体】富客户端应用程序GUI框架 JavaFX 2.0 简介

JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架,它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能,旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出,2011 年 10 月发布了2.0 版本。JavaFX 2.0…

OpenLayers使用

初学ol,实现了高德地图不同图层的切换、交互性地图飞行以及加载本地JSON数据。 说一下不同图层切换的想法: 1.对于标准地图和卫星地图:二者最初便挂载到map上,两个图层是叠加显示的;当点击按钮时,其实是使…

VSCode里python代码不扩展/级联了的解决办法

如图 解决办法:重新下载新的扩展工具 步骤如下 1、在左边工具栏打开Extensions 2、搜索框输入python,选择别的扩展工具,点击Install - 3在扩展工具所在的目录下,新建一个文件,就可以用了

指定IP地址通过远程桌面访问WINDOWS10

1:登录Windows10系统,在控制面板找到系统和安全,打开Windows Defender防火墙。 2:点击感觉设置。 3:在入站规则中,找到远程桌面。查看自己的网络现在是公用,域,还是专用。选择对应的网络。 4&am…

Oracle EBS PO采购订单预审批状态处理

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 采购订单状态:预审批 采购订单流程报错如下: po.plsql.PO_DOCUMENT_ACTION_AUTH.approve:90:archive_po not successful - po.plsql.PO_DOCUMENT_ACTION_PVT.do_action:110:unexpected error in acti…

js生成器,迭代器和可迭代对象详解

1.生成器函数和生成器 生成器函数是可以返回一个可迭代对象的特殊函数, 生成器是一个特殊的迭代器, 在js中可以使用function*来定义一个非连续执行的函数作为迭代算法, function* name() {yield value;yield value;yield value; }name: 函…

基于YOLOv5的人脸目标检测

本文是在之前的基于yolov5的人脸关键点检测项目上扩展来的。因为人脸目标检测的效果将直接影响到人脸关键点检测的效果,因此本文主要讲解利用yolov5训练人脸目标检测(关键点检测可以看我人脸关键点检测文章) 基于yolov5的人脸关键点检测:人脸关键点检测…

ROS学习笔记(18):建图与定位(2)

0.前言 上文提到现在的我们已经进入到了SLAM领域的学习,会涉及到大量专业知识,作为一个自学的大三(好吧也快大四了)萌新并不能保证每次文章的专业性和准确性,所以,本人推荐大家能自己去查阅一些相关书籍和…

TOB传输、承载网拓扑图

1、用户面:GNODEB>UPE>SPE>NPE>UPF>CMNET网 2、控制面:GNODEB>UPE>SPE>NPE>IP承载网>核心网

充分利用智慧校园人事系统,提升党政职务管理

智慧校园人事系统中的党政职务管理功能,是专为高校及教育机构设计的,旨在高效、精确地处理与党政职务相关的各类事务,包括职务任命、任期管理、职责分配、考核评估等,以信息化手段促进党务及行政工作的透明化、规范化。 该模块首先…

redis主从复制哨兵模式集群管理

主从复制: 主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡&…

像学Excel 一样学 Pandas系列-创建数据分析维度

嗨,小伙伴们。又到喜闻乐见的Python 数据分析王牌库 Pandas 的学习时间。按照数据分析处理过程,这次轮到了新增维度的部分了。 老样子,我们先来回忆一下,一个完整数据分析的过程,包含哪些部分内容。 其中&#xff0c…

好久不见!写了一个自动截图神器~【附源码】

文章目录 前言新增功能介绍截图功能快捷键设置 程序设计和使用介绍操作菜单栏选择点击坐标点选择图片选择截图区域快捷键设置 表格循环次数状态栏 使用案例源代码 前言 好久没更新文章了。上一次更新是在4月16日差不多,也只是写了一个错误集,没什么太多…

【Python机器学习】模型评估与改进——在模型选择中使用评估指标

我们通常希望,在使用GridSearchCV或cross_val_score进行模型选择时能够使用AUC等指标。scikit-learn提供了一种非常简单的实现方法,那就是scoring参数,它可以同时用于GridSearchCV和cross_val_score。你只需要提供一个字符串,用于…

基于Vue的MOBA类游戏攻略分享平台

你好呀,我是计算机学姐码农小野!如果有相关需求,可以私信联系我。 开发语言:Java 数据库:MySQL 技术:Java技术、SpringBoot框架、B/S模式、Vue.js 工具:MyEclipse、MySQL 系统展示 首页 用…

大模型技术在辅助学习中的应用

大模型技术在辅助学习中的应用场景非常广泛,以下是一些典型示例。大模型技术在辅助学习中具有广阔的应用前景,可以为学生提供更加个性化、智能化和高效的学习体验。随着大模型技术的不断发展,我们可以期待在未来看到更多创新应用。北京木奇移…
最新文章