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.mzph.cn/bicheng/39997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux高并发服务器开发(十)反应堆模型和线程池模型

文章目录 1 epoll反应堆2 线程池流程代码 3 复杂版本线程池代码 1 epoll反应堆 文件描述符 监听事件 回调函数 进行封装 创建socket设置端口复用绑定监听创建epoll树将监听文件描述符lfd上epoll树,对应的事件节点包括:文件描述符,事件epoll…

Taogogo Taocms v3.0.2 远程代码执行漏洞(CVE-2022-25578)

前言 CVE-2022-25578 是一个存在于 Taogogo Taocms v3.0.2 中的代码注入漏洞。此漏洞允许攻击者通过任意编辑 .htaccess 文件来执行代码注入。 漏洞详情 漏洞描述:攻击者可以利用此漏洞上传一个 .htaccess 文件到网站,并在文件中注入恶意代码&#xf…

Memcached缓存键命名规范:最佳实践与技巧

引言 Memcached是一个广泛使用的高性能分布式内存缓存系统,它通过键值对的方式存储数据,以提高数据检索速度。正确的缓存键命名对于维护Memcached缓存的效率和可管理性至关重要。本文将详细介绍Memcached缓存键的命名规范和最佳实践。 Memcached缓存键…

苹果手机怎么刷机?适合小白的刷机办法!

自己的苹果手机用时间长了,有些人想要为自己的手机重新刷新一下,但又不知道怎么刷机。不要慌现在就来给大家详细介绍一下苹果手机怎么刷机,希望可以帮助到大家。 iPhone常见的刷机方式,分为iTunes官方和第三方软件两种刷机方式。 …

【elementui】记录解决el-tree开启show-checkbox后,勾选一个叶结点后会自动折叠的现象

第一种解决方案&#xff1a;设置default-expand-keys的值为当前选中的key值即可 <el-treeref"tree"class"checkboxSelect-wrap":data"treeData"show-checkboxnode-key"id":expand-on-click-node"true":props"defau…

游戏云服务器为什么经常卡顿不流畅?

游戏云服务器经常出现卡顿或不流畅的情况可能是由多种因素造成的。以下是一些常见的原因&#xff1a; 网络问题 - 带宽不足&#xff1a;如果服务器的带宽不足以支持高峰时段的所有玩家同时在线&#xff0c;就会导致数据传输缓慢&#xff0c;引起卡顿。 - 网络延迟&#xff1a;网…

第T3周:天气识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、前期工作 本文将采用CNN实现多云、下雨、晴、日出四种天气状态的识别。较上篇文章&#xff0c;本文为了增加模型的泛化能力&#xff0c;新增了Dropout层并…

三、文件操作、错误与异常处理等(爬虫及数据可视化)

三、文件操作、错误与异常处理等&#xff08;爬虫及数据可视化&#xff09; 1&#xff0c;文件操作2&#xff0c;错误与异常 1&#xff0c;文件操作 学习文件操作的相关知识&#xff0c;将一些数据存起来&#xff0c;打开、关闭、读取、写入&#xff0c;重命名、删除等操作在o…

拉曼光谱入门:1.光谱的分类与散射光谱发展史

一、光谱是什么&#xff1f; 在一个宁静的午后&#xff0c;年轻的艾萨克牛顿坐在他母亲花园里的一棵苹果树下&#xff0c;手握一块精致的三棱镜。他沉思着光的奥秘&#xff0c;意识到光并非单一的白色&#xff0c;而是一种由多彩色组成的复杂结构。 他决心进行一次实验&#xf…

浅析C++函数重载

浅析C函数重载 C语言和C函数调用的不同 C语言会进行报错 C能成功运行并且自动识别类型 由此可以看出&#xff0c;C在函数调用时进行了调整&#xff0c;使其支持函数重载&#xff0c;那么我们就来看看进行了哪些调整吧&#x1f60e; 分析函数调用 首先我们要知道&#xff0c…

SQL中常用的内置函数

SQL中常用的内置函数 在SQL&#xff08;结构化查询语言&#xff09;中&#xff0c;有许多内置函数可用于各种数据操作和计算。以下是SQL中常用的函数。 一.字符串操作、数值计算、日期处理 COUNT(): 统计行数。 SELECT COUNT(*) FROM employees;SUM(): 计算数值列的总和。 S…

2024企业数据资产化及数据资产入表方案梳理

01 数据资产入表&#xff1a;是一个将组织的各类数据资产进行登记、分类、评估和管理的流程。 数据资产包括&#xff1a;客户信息、交易记录、产品数据、财务数据等。 做个比喻吧&#xff1a;数据资产入表就像是给公司的数据资产做“人口普查”—— ①找出公司有哪些数据找…

macos m2 百度paddleocr文字识别 python

创建了一个虚拟环境&#xff1a;conda create -n orc python3.11.7 进入虚拟环境后执行2条命令 pip install paddleocr -i https://pypi.tuna.tsinghua.edu.cn/simple pip install paddlepaddle -i https://pypi.tuna.tsinghua.edu.cn/simple​ ​ 安装好后&#xff0c;在网…

204.贪心算法:分发饼干(力扣)

以下来源于代码随想录 class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 对孩子的胃口进行排序sort(g.begin(), g.end());// 对饼干的尺寸进行排序sort(s.begin(), s.end());int index s.size() - 1; // 从最大的饼…

Java使用分布式锁来做数据库事务控制

步骤如下&#xff1a; 1&#xff09;选择合适的分布式锁实现&#xff1a;常见的分布式锁实现包括ZooKeeper、Redis和基于数据库等。根据具体情况选择最佳方案。 2&#xff09;获取分布式锁&#xff1a;在需要进行操作时&#xff0c;首先尝试获取分布式锁。如果成功获取到&#…

严蔚敏数据结构(C语言版)吴伟民宁编著清华大学计算机系列教材+题集+配套题库+笔记+习题PDF电子版

今天分享的是 严蔚敏数据结构&#xff08;C语言版&#xff09;题集配套题库笔记习题PDF电子版 注&#xff1a;本资源搜集于网络&#xff0c;仅供学习交流&#xff0c;严禁用于商业用途 内容简介&#xff1a; “数据结构”是计算机程序设计的重要理论技术基础&#xff0c;它…

ArcTs布局入门04——相对布局 媒体查询

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧 扫描下面的二维码关注公众号。 本文将探讨相对布局与媒体查询&#xff0c;为啥把他们放到一起呢&#xff1f;主要是因为相对布局在响应式的场景下做得不太好&#xff0c;一般情况下和媒体查询&#xff08;不同尺…

MySQL之备份与恢复(二)

备份与恢复 定义恢复需求 如果一切正常&#xff0c;那么永远也不需要考虑恢复。但是&#xff0c;一旦需要恢复&#xff0c;只有世界上最好的备份系统是没用的&#xff0c;还需要一个强大的恢复系统。 不幸的是&#xff0c;让备份系统平滑工作比构造良好的恢复过程和工具更容易…

OCR是什么,主要应用和未来发展趋势

OCR&#xff0c;即光学字符识别&#xff08;Optical Character Recognition&#xff09;&#xff0c;是一种能够将图像文件中的文字资料转化为电子文本的技术。它广泛应用于数字化文档管理、自动化数据录入、智能识别等多个领域&#xff0c;涉及的主要技术包括图像预处理、特征…

【NBU大三下期末考试实录】

软件测试 任课老师&#xff1a;WXH&#xff0c;形式&#xff1a;开卷&#xff08;中文试卷&#xff0c;可携带中文书籍&#xff09; 复习建议&#xff1a;由于是开卷考&#xff0c;不需要过早复习&#xff0c;建议考前照着上课的PPT复习&#xff0c;大致有个概念即可&#xff…