《Lua快速入门》6.Lua的数据结构

Lua 中的数据结构包括数组、列表、栈、队列等。数组是通过表实现的,列表是一种特殊的数组,栈和队列是基于表的简单数据结构。

Lua 的数据结构

1. 数组与列表

1.1 数组的概念

在 Lua 中,数组是通过表(Table)实现的。数组是一种线性数据结构,元素通过整数索引访问。

1.2 数组的创建

数组可以通过直接初始化或动态添加元素来创建。

-- 直接初始化
local arr = {1, 2, 3, 4, 5}

-- 动态添加元素
local arr = {}
for i = 1, 5 do
    arr[i] = i
end

1.3 数组的访问

通过索引访问数组元素,索引从 1 开始。

print(arr[1])  -- 输出: 1
print(arr[3])  -- 输出: 3

1.4 数组的遍历

使用 ipairs 或 for 循环遍历数组。

for i, v in ipairs(arr) do
    print(i, v)
end

1.5 数组的操作

  • 插入元素:使用 table.insert。
    table.insert(arr, 6)  -- 在末尾插入
    table.insert(arr, 2, 1.5)  -- 在指定位置插入
    
  • 删除元素:使用 table.remove。
    table.remove(arr, 2)  -- 删除第二个元素
    
  • 排序:使用 table.sort。
    table.sort(arr)
    

1.6 多维数组

Lua 支持多维数组,通过嵌套表实现。

local matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}
print(matrix[2][3])  -- 输出: 6

2. 栈与队列

2.1 栈的概念

栈是一种后进先出(LIFO)的数据结构,支持压栈(push)和弹栈(pop)操作。

2.2 栈的实现

使用表实现栈。

local stack = {}

-- 压栈
function push(value)
    table.insert(stack, value)
end

-- 弹栈
function pop()
    return table.remove(stack)
end

push(1)
push(2)
print(pop())  -- 输出: 2

2.3 队列的概念

队列是一种先进先出(FIFO)的数据结构,支持入队(enqueue)和出队(dequeue)操作。

2.4 队列的实现

使用表实现队列。

local queue = {}

-- 入队
function enqueue(value)
    table.insert(queue, value)
end

-- 出队
function dequeue()
    return table.remove(queue, 1)
end

enqueue(1)
enqueue(2)
print(dequeue())  -- 输出: 1

3. 字符串操作

3.1 字符串的基本操作

Lua 中的字符串是不可变的,所有操作都会返回一个新的字符串。

3.1.1 字符串连接

使用 .. 运算符连接字符串。

local str1 = "Hello"
local str2 = "Lua"
local str3 = str1 .. " " .. str2
print(str3)  -- 输出: Hello Lua
3.1.2 字符串长度

使用 # 运算符获取字符串长度。

local str = "Hello"
print(#str)  -- 输出: 5
3.1.3 字符串截取

使用 string.sub 函数截取子串。

local str = "Hello, Lua"
local sub = string.sub(str, 8, 10)
print(sub)  -- 输出: Lua

3.2 字符串查找与替换

3.2.1 查找子串

使用 string.find 函数查找子串。

local str = "Hello, Lua"
local start, finish = string.find(str, "Lua")
print(start, finish)  -- 输出: 8 10
3.2.2 替换子串

使用 string.gsub 函数替换子串。

local str = "Hello, Lua"
local new_str = string.gsub(str, "Lua", "World")
print(new_str)  -- 输出: Hello, World

3.3 字符串格式化

使用 string.format 函数格式化字符串。

local name = "Lua"
local version = 5.4
local str = string.format("Language: %s, Version: %.1f", name, version)
print(str)  -- 输出: Language: Lua, Version: 5.4

3.4 字符串分割

Lua 没有内置的字符串分割函数,但可以通过 string.gmatch 实现。

local str = "one,two,three"
local result = {}
for word in string.gmatch(str, "[^,]+") do
    table.insert(result, word)
end
print(table.concat(result, " "))  -- 输出: one two three

3.5 字符串模式匹配

Lua 使用模式(Pattern)进行字符串匹配,类似于正则表达式。

3.5.1 常用模式
  • %a:字母。
  • %d:数字。
  • %s:空白字符。
  • %w:字母或数字。
  • %p:标点符号。
3.5.2 模式匹配示例
local str = "Lua 5.4"
for word in string.gmatch(str, "%a+") do
    print(word)  -- 输出: Lua
end

4. 链表、哈希表与优先队列

表(Table)的灵活性不仅限于数组和栈队列。掌握链表、哈希表和优先队列的实现,是处理更复杂问题的基础。

4.1 链表的实现

-- 单向链表节点
Node = {}
Node.__index = Node

function Node:new(value)
    return setmetatable({value = value, next = nil}, Node)
end

-- 链表操作
LinkedList = {}
LinkedList.__index = LinkedList

function LinkedList:new()
    return setmetatable({head = nil, size = 0}, LinkedList)
end

function LinkedList:prepend(value)
    local node = Node:new(value)
    node.next = self.head
    self.head = node
    self.size = self.size + 1
end

function LinkedList:remove(value)
    local current = self.head
    local prev = nil
    while current do
        if current.value == value then
            if prev then
                prev.next = current.next
            else
                self.head = current.next
            end
            self.size = self.size - 1
            return true
        end
        prev = current
        current = current.next
    end
    return false
end

function LinkedList:find(value)
    local current = self.head
    while current do
        if current.value == value then
            return current
        end
        current = current.next
    end
    return nil
end

function LinkedList:iterate()
    local current = self.head
    return function()
        if current then
            local value = current.value
            current = current.next
            return value
        end
    end
end

4.2 哈希表(直接用表即可)

Lua 的表本身就是哈希表与数组的混合体。键排除 nil 和 NaN,不能把这一例推广为可用任意浮点值作键。nil 值删除项,false 值保留:

local hash = {}
hash["key"] = "value"
hash[42] = "number key"
hash[true] = "boolean key"

-- 遍历
for k, v in pairs(hash) do
    print(k, v)
end

4.3 优先队列(最小堆)

PriorityQueue = {}
PriorityQueue.__index = PriorityQueue

function PriorityQueue:new()
    return setmetatable({heap = {}}, PriorityQueue)
end

function PriorityQueue:push(priority, value)
    table.insert(self.heap, {priority = priority, value = value})
    self:_sift_up(#self.heap)
end

function PriorityQueue:pop()
    if #self.heap == 0 then return nil end
    local min = self.heap[1]
    self.heap[1] = self.heap[#self.heap]
    table.remove(self.heap)
    self:_sift_down(1)
    return min.priority, min.value
end

function PriorityQueue:_sift_up(i)
    while i > 1 do
        local parent = math.floor(i / 2)
        if self.heap[i].priority >= self.heap[parent].priority then break end
        self.heap[i], self.heap[parent] = self.heap[parent], self.heap[i]
        i = parent
    end
end

function PriorityQueue:_sift_down(i)
    local size = #self.heap
    while true do
        local min = i
        local left, right = i * 2, i * 2 + 1
        if left <= size and self.heap[left].priority < self.heap[min].priority then
            min = left
        end
        if right <= size and self.heap[right].priority < self.heap[min].priority then
            min = right
        end
        if min == i then break end
        self.heap[i], self.heap[min] = self.heap[min], self.heap[i]
        i = min
    end
end

5. 数据结构复杂度对比

数据结构访问插入删除查找Lua 实现方式
数组(Array)O(1)O(n)O(n)O(n)table 整数索引
栈(Stack)O(1) 栈顶O(1)O(1)—table.insert/remove
队列(Queue)O(1) 队首O(1) 队尾O(n)—table.insert/remove(,1)
链表(LinkedList)O(n)O(1) 头插O(n)O(n)自定义节点结构
哈希表(Hash)O(1) 均摊O(1) 均摊O(1) 均摊O(1) 均摊table 键值对
优先队列(Heap)O(1) 最小值O(log n)O(log n)—自定义堆结构

选择数据结构时,优先使用 Lua 原生表(数组 + 哈希混合)。只有当需要频繁在开头插入或删除时,才考虑链表;需要按优先级处理时,才实现堆。

4. 总结

Lua 的数据结构灵活而强大,通过表(Table)可以实现数组、列表、栈、队列、链表、优先队列等多种数据结构。字符串操作功能丰富,支持连接、截取、查找、替换、格式化等操作。掌握这些数据结构的使用方法,是编写高效 Lua 程序的关键。


继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「lua」更多文章

  1. Lua 时间日期处理与时区
  2. Lua 在嵌入式与 IoT 中的开发实践
  3. Lua 与 WebAssembly 互操作