当前位置: 首页 > news >正文

Lua 第14部分 数据结构

14.1  数组

        Lua 语言中的表并不是一种数据结构,它们是其他数据结构的基础。我们可以用 Lua 语言中的表来实现其他语言提供的数据结构,如数组、记录、列表、队列、集合等。而且,用Lua 语言中的表实现这些数据结构还很高效。
        在像 C 和 Pascal 这样更加传统的语言中,通常使用数组和列表(列表=记录+指针)来实现大多数数据结构。虽然在 Lua 语言中也可以使用表来实现数组和列表,但表实际上比数组和列表强大得多。使用表时,很多算法可以被简化。例如,由于表本身就支持任意数据类型的直接访问,因此我们很少在 Lua 语言中编写搜索算法。
        学习如何高效地使用表需要花费一点时间。这里,我们先来学习如何通过表来实现一些典型的数据结构并给出一些使用这些数据结构的例子。首先,我们学习数组和列表,这并不是因为需要它们作为其他结构的基础,而是因为大多数程序员已经对数组和列表比较熟悉了。

        在 Lua 语言中,简单地使用整数来索引表即可实现数组。因此,数组的大小不用非得是固定的,而是可以按需增长的。通常,在初始化数组时就间接地定义了数组的大小。例如,在执行了以下的代码后,任何访问范围 1 ~ 1000 之外的元素都会返回 nil 而不是 0:

local a = {}		-- 新数组
for i = 1, 1000 doa[i] = 0
end

长度运算符(#)正是基于此来计算数组大小的:

print(#a)
> 1000

可以使用 0 、1 或其他任何值来作为数组的起始索引 :

-- 创建一个索引范围为-5~5的数组
a = {}
for i = -5, 5 doa[i] = 0
end

        不过,在 Lua 语言中一般以 1 作为数组的起始索引,Lua 语言的标准库和长度运算符都遵循这个惯例。 如果数组的索引不从 1 开始,那就不能使用这些机制

        可以通过表构造器在一句表达式中同时创建和初始化数组:

squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}

这种表构造器根据需求要多大就能多大。在 Lua 语言中,利用数据描述文件创建包含几百万个元素组成的构造器很常见。

14.2  矩阵及多维数组

      在 Lua 语言中,有两种方式来表示矩阵。第一种方式是使用一个不规则数组,即数组的数组,也就是一个所有元素均是另一个表的表。例如,可以使用如下的代码来创建一个全 0 元素的 N*M维矩阵:

local mt = {}
for i = 1, N dolocal row = {}mt[i] = rowfor j = 1, M dorow[j] = 0end
end

由于表在 Lua 语言中是一种对象,因此在创建矩阵时必须显式地创建每一行。一方面,这比在 C 语言中直接声明一个多维数组更加具体;另 一方面,这也给我们提供了更多的灵活性。例如,只需将前例中的内层循环改为 for j=1, i do ... end 就可以创建一个三角形矩阵。使用这套代码,三角形矩阵较原来的矩阵可以节约一半的内存。

        在 Lua 中表示矩阵的第二种方式是将两个索引合并为一个。典型情况下,我们通过将第一个索引乘以一个合适的常量再加上第二个索引来实现这种效果。在这种方式下,我们可以使用以下的代码来创建一个全 0 元素的 N×M 维矩阵:

local mt = {}
for i = 1, N dolocal aux = (i - 1) * Mfor j = 1, M domt[aux + j] = 0end
end

        应用程序中经常会用到稀疏矩阵,这种矩阵中的大多数元素是 0 或 nil。例如,我们可以使用邻接矩阵来表示图。当矩阵( m, n )处元素的值为x时,表示图中的节点 m 和 n 是相连的,连接的权重为 x ;若上述的两个节点不相连,那么矩阵的( m,n)处元素的值为 nil。如果要表示一个具有 1 万个节点的图(其中每个节点有 5 个邻居),那么需要一个能包含 1 亿个元素的矩阵( 10000 列×10000 行的方阵),但是其中大约只有 5 万个元素不为nil(每行有 5 列不为 nil ,对应每个节点有 5 个邻居)。许多有关数据结构的书籍都会深入地讨论如何实现这种稀疏矩阵而不必浪费 800MB 内存空间,但在 Lua 语言中却很少需要用到那些技巧。这是因为,我们使用表实现数组而表本来就是稀疏的。在第一种实现中(表的表),需要 1 万个表,每个表包含 5 个元素,总共 5 万个元素。在第二种实现中,只需要一个表,其中包含 5 万个元素。无论哪种实现,都只有非 nil 的元素才占用空间。

        由于在有效元素之间存在空洞( nil 值),因此不能对稀疏矩阵使用长度运算符。这没什么大不了的,即使我们能够使用长度运算符,最好也不要那么做。对于大多数针对稀疏矩阵的操作来说,遍历空元素是非常低效的。相反,可以使用 pairs 来只遍历非 nil 的元素。例如,考虑如何进行由不规则数组表示的稀疏矩阵的矩阵乘法。

        假设矩阵 a[M,K]乘以矩阵 b[K,N]的结果为矩阵 c[ M, N],常见的矩阵相乘算法形如 :

for i = 1, M dofor j = 1, N doc[i][j] = 0for k = 1, K doc[i][j] = c[i][j] + a[i][k] * b[k][j]endend
end

外层的两个循环遍历了整个结果矩阵,然后使用内层循环计算每一个元素的值。

        对于使用不规则矩阵实现的稀疏矩阵,内层循环会有问题。由于内层循环遍历的是一列b而不是一行,因此不能在此处使用 pairs :这个循环必须遍历每一行来检查对应的行是否在对应列中有元素。除了遍历了少量非 0 元素以外,这个循环还遍历了所有的 0 元素。(由于不知道元素的空间位置,所以在其他场景下遍历一列也可能会有问题。)

        以下的算法与之前的示例非常类似,但是该算法调换了两个内层循环的顺序。通过这个简单的调整,该算法避免了遍历列 :

for i = 1, M dofor k = 1, K dofor j = 1, N doc[i][j] = c[i][j] + a[i][k] * b[k][j]endend
end

这样,中间的一层循环遍历行 a[i] ,而内层循环遍历行 b[k] 。这两个遍历都可以使用 pairs来实现仅遍历非 0 元素。由于一个空的稀疏矩阵本身就是使用 0 填充的,所以对结果矩阵 c 的初始化没有任何问题。

        示例14.1展示了上述算法的完整实现,其中使用了 pairs 来处理稀疏的元素。这种实现只访问非 nil 元素,同时结果也是稀疏矩阵。此外,下面的代码还删去了结果中偶然为 0 的元素 。

示例 14.1 稀疏矩阵相乘:

function mult (a, b)local c = {}			-- 结果矩阵for i = 1, #a dolocal resultlint = {}			-- 即'c[i]'for k, va in pairs(a[i]) do			-- 'va'即a[i][k]for j, vb in pairs(b[k]) do			-- 'vb'即b[k][j]local res = (resultlint[j] or 0) + va * vbresultlint[j] = (res ~= 0) and res or nilendendc[i] = resultlintendreturn c
end

14.3  链表

        由于表是动态对象,所以在 Lua 语言中可以很容易地实现链表。我们可以把每个节点用一个表来表示(也只能用表表示),链接则为一个包含指向其他表的引用的简单表字段。例如,让我们实现一个单链表,其中每个节点具有两个字段value 和 next 。最简单的变量就是根节点 :

list = nil

要在表头插入一个值为 v 的元素,可以使用如下的代码 :

list = {next = list, value = v}

可以通过如下的方式遍历链表:

local l = list
while l dovisit l.valuel = l.next
end

        诸如双向链表环形表等其他类型的链表也很容易实现。不过,由于通常无须链表即可用更简单的方式来表示数据,所以在 Lua 语言中很少需要用到这些数据结构。例如,我们可以通过一个无界数组来表示栈

14.4  队列及双端队列

        在 Lua 语言中实现队列的一种简单方法是使用 table 标准库中的函数 insert和 remove 。这两个函数可以在一个数组的任意位置插入或删除元素,同时根据所做的操作移动其他元素。不过,这种移动对于较大的结构来说开销很大。一种更高效的实现是使用两个索引,一个指向第一个元素,另一个指向最后一个元素。使用这种实现方式,我们就可以像在示例 14.2 中所展示的那样以 O(1)时间复杂度同时在首尾两端插入或删除元素了 。

示例 14.2 一个双端队列

function listNew ()return {first = 0, last = -1}
endfunction pushFirst (list, value)local first = list.first - 1list.first = firstlist[first] = value
endfunction pushLast (list, value)local last = list.last + 1list.last = lastlist[last] = value
endfunction popFirst (list)local first = list.firstif first > list.last then error("list is empty") endlocal value = list[first]list[first] = nil					-- 使得元素能够被垃圾回收list.first = first + 1return value
endfunction popLast (list)local last = list.lastif list.first > last then error("list is empty") endlocal value = list[last]list[last] = nil					-- 使得元素能够被垃圾回收list.last = last - 1return value
end

        如果希望严格地遵循队列的规范使用这个结构,那么就只能调用 pushLast 和 popFirst 函数, first 和 last 都会不断地增长。不过,由于我们在 Lua 语言中使用表来表示数组,所以我们既可以在 1~20 的范围内对数组进行索引,也可以在 16777201~16777220 的范围内索引数组。 对于一个 64 位整型数而言,以每秒 1000 万次的速度进行插入也需要运行 3 万年才会发生溢出的问题。

14.5  反向表

        正如此前提到的,我们很少在 Lua 语言中进行搜索操作。相反,我们使用被称为索引表或反向表的数据结构。

        假设有一个存放了一周每一天名称的表:

days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}

如果想要将一周每一天的名称转换为其在一周里的位置,那么可以通过搜索这个表来寻找指定的名称。不过,一种更高效的方式是构造一个反向表,假定为revDays,该表中的索引为一周每一天的名称而值为其在一周里的位置。 这个表形如 :

revDays = {["Sunday"] = 1, ["Monday"] = 2,["Tuesday"] = 3, ["Wednesday"] = 4,["Thursday"] = 5, ["Friday"] = 6,["Saturday"] = 7}

然后,只需要直接在反向表中根据名称进行索引就可以了:

x = "Tuesday"
print(revDays[x])
> 3

当然,这个反向表不用于工声明,可以从原始的表中自动地构造出反向表:

revDays = {}
for k,v in pairs(days) dorevDays[v] = k
end

上例中的循环会对每个元素 days 进行赋值,变量 k 获取到的是键 (1, 2, ... )而变量 v 获取到的是值(” Sunday ”,” Monday ”,... )。

14.6  集合与包

        假设我们想列出一个程序源代码中的所有标识符,同时过滤掉其中的保留字。一些 C 程序员可能倾向于使用字符串数组来表示保留字集合,然后搜索这个数组来决定某个单词是否属于该集合。为了提高搜索的速度,他们还可能会使用二叉树来表示该集合。

        在 Lua 语言中,还可以用一种高效且简单的方式来表示这类集合,即将集合元素作为索引放入表中。那么,对于指定的元素无须再搜索表,只需用该元素检索表并检查结果是否为nil即可。以上述需求为例,代码形如:

reserved = {["while"] = true, ["if"] = true,["else"] = true, ["do"] = true,
}for w in string.gmatch(s, "[%a_][%w_]*") doif not reserved[w] thendo something with 'w'		-- 'w'不是一个保留字end
end

(在定义 reserved 时,由于 while 是 Lua 语言的保留字,所以不能直接写成 while=true,而应该写为 [" while"]= true 。 )

        我们可以借助一个辅助函数来构造集合,使得初始化过程更清晰 :

function Set (list)local set = {}for _, l in ipairs(list) do set[l] = true endreturn set 
endreserved = Set{"while", "end", "function", "local",}

        我们还可以使用另一个集合来保存标识符 :

local ids = {}
for w in string.gmatch(s, "[%a_][%w_]*") doif not reserved[w] thenids[w] = trueend
end-- 输出每一个标识符
for w in pairs(ids) do print(w) end

        包( bag ), 也被称为多重集合( multiset ),与普通集合的不同之处在于其中 的元素可以
出现多次。在 Lua 语言中,包的简单表示类似于此前集合的表示,只不过其中的每一个键都有一个对应的计数器。如果要插入一个元素,可以递增其计数器:

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

只有当计数器存在且大于 0 时我们才会保留计数器。

14.7  字符串缓冲区

      假设我们正在开发一段处理字符串的程序,比如逐行地读取一个文件。典型的代码可能形如 :

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

虽然这段 Lua 语言代码看似能够正常工作,但实际上在处理大文件时却可能导致巨大的性能开销 。例如,在笔者的新机器上用这段代码读取一个 4.5MB 大小的文件需要超过 30 秒的时间 。

        这是为什么呢?为了搞清楚到底发生了什么,让我们想象一下读取循环中发生了什么。假设每行有 20 字节,当我们读取了大概 2500 行后,buff 就会变成一个 50KB 大小的字符串。在 Lua 语言中进行字符串连接 buff ..  line  .."\n" 时,会创建一个 50020 字节的新字符串,然后从 buff 中复制 50000 字节中到这个新字符串中。这样,对于后续的每一行,Lua 语言都需要移动大概 50KB 且还在不断增长的内存。因此,该算法的时间复杂度是二次方的。在读取了 100 行(仅 2KB )以后,Lua 语言就已经移动了至少 5MB 内存。当 Lua 语言完成了 350KB 的读取后,它已经至少移动了 50 GB 的数据。(这个问题不是 Lua 语言特有的:在其他语言中,只要字符串是不可变值,就会出现类似的问题,其中最有名的例子就是 Java 。 )

       在继续学习之前,我们必须说明,上述场景中的情况并不常见。对于较小的字符串,上述循环并没什么问题。 当读取整个文件时, Lua 语言提供了带有参数的函数 io.read("a") 来一次性地读取整个文件。不过,有时候我们必须面对这个问题。Java 提供了 StringBuffer类来解决这个问题;而在 Lua 语言中,我们可以把一个表当作字符串缓冲区,其关键是使用函数 table.concat,这个函数会将指定列表中的所有字符串连接起来并返回连接后的结果。使用函数 concat 可以这样重写上述循环 :

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

虽然函数 concat 能够在字符串之间插入分隔符,但我们还需要增加最后一个换行符。最后一次字符串连接创建了结果字符串的一个副本,这个副本可能已经相当长了。虽然没有直接的选项能够让函数 concat 插入这个额外的分隔符,但我们可以想办法绕过,只需在字符串 t 后面添加一个空字符串就行了:

t[#t + 1] = ""
s = table.concat( t, "\n")

现在,正如我们所期望的那样,函数 concat 会在结果字符串的最后添加一个换行符。

14.8 图形

      像其他现代编程语言一样, Lua 语言也允许开发人员使用多种实现表示图,每种实现都有其所适用的特定算法。这里,我们接下来将介绍一种简单的面向对象的实现方式,在这种实现中使用对象来表示节点(实际上是表)、将边(arc )表示为节点之间的引用。

      我们使用一个由两个字段组成的表来表示每个节点,即 name(节点的名称)和 adj(与此节点邻接的节点的集合)。由于我们会从一个文本文件中加载图对应的数据,所以需要能够根据节点的名称来寻找指定节点的方法。因此,我们使用了一个额外的表来建立节点和节点名称之间的映射。函数 name2node 可以根据指定节点的名称返回对应的节点:

local function name2node (graph, name)local node = graph[name]if not node then-- 节点不存在,创建一个新节点node = {name = name, adj = {}}gra[name] = nodeendreturn node
end

示例 14.3 展示了构造图的函数。

function readgrap ()local graph = {}for line in io.lines() do-- 把一行分隔为两个名字local namefrom, nameto = string.match(line, "(%S+)%s+(%S+)")-- 找到对应的节点local from = name2node(grap, namefrom)local to = name2node(grap, nameto)-- 把'to'增加到邻接集合'from'中from.adj[to] = trueendreturn graph
end

        该函数逐行地读取一个文件,文件的每一行中有两个节点的名称,表示从第 1 个节点到第2个节点有一条边。对于每一行,调用函数 string.match 将一行中的两个节点的名称分开,然后根据名称找到对应的节点(如果需要的话则创建节点),最后将这些节点连接在一起。

示例 14.4展示了一个使用这种图的算法。

function findpath (curr, to, path, visited)path = path or {}visited = visited or {}if visited[curr] then		-- 是否节点已被访问?return nil				-- 不存在路径endvisited[curr] = true		-- 标记节点为已被访问path[#path + 1] = curr		-- 增加到路径中if curr == to then			-- 是否是最后一个节点?return path end-- 尝试所有的邻接节点for node in pairs(curr.adj) dolocal p = findpath(node, to, path, visited)if p then return p endendtable.remove(path)			-- 从路径中删除节点
end

      函数 findpath 使用深度优先遍历搜索两个节点之间的路径。该函数的第 1 个参数是当前节点,第 2 个参数是目标节点,第 3 个参数用于保存从起点到当前节点的路径,最后一个参数为所有已被访问节点的集合(用于避免回路)。 请读者注意分析该算法是如何不通过节点名称而直接对节点进行操作的。例如,visited 是一个节点的集合,而不是节点名称的集合。类似地,path 也是一个节点的列表。

        为了测试上述代码,我们编写一个打印一条路径的函数,再编写一些代码让上述所有代码跑起来:

function printpath (path)for i = 1, #path doprint(path[i].name)end
endg = readgrap()
a = name2node(g, "a")
b = name2node(g, "b")
p = findpath(a, b)
if p then printpath(p) end

相关文章:

Lua 第14部分 数据结构

14.1 数组 Lua 语言中的表并不是一种数据结构,它们是其他数据结构的基础。我们可以用 Lua 语言中的表来实现其他语言提供的数据结构,如数组、记录、列表、队列、集合等。而且,用Lua 语言中的表实现这些数据结构还很高效。 在像 C 和…...

杭州数据库恢复公司之Dell服务器RAID5阵列两块硬盘损坏报警离线

外地客户寄过来六块SAS服务器硬盘,说是组了RAID5磁盘阵列的戴尔DELL服务器突然崩溃了,更换阵列卡后开始可以进入系统,不过有一块盘亮黄灯报警,工程师打算把服务器放回机柜后更换新硬盘,但再重启就无法进系统了&#xf…...

linux 内核 debugfs 使用介绍

一:概述 debugfs 是 Linux 内核提供的一个特殊的虚拟文件系统,用于 暴露内核模块(如驱动)内部的调试信息或控制接口,供开发者、调试人员实时查看和排查问题。即 debugfs 就是一个“调试专用的 /proc 或 /sys”&#xf…...

MarkItDown:如何高效将各类文档转换为适合 LLM 处理的 Markdown 格式

MarkItDown:如何高效将各类文档转换为适合 LLM 处理的 Markdown 格式 引言项目概述分析基本信息主要功能支持的文件格式技术架构 为什么选择 Markdown?核心功能详解1. 文档转换机制2. LLM 集成能力3. 多种转换选项4. 插件系统 安装和使用教程安装可选依赖…...

解锁未来工作方式:什么是 AI Agent?| Unlocking the Future of Work: What Are AI Agents?

🇨🇳 解锁未来工作方式:什么是 AI Agent?| 🇺🇸 Unlocking the Future of Work: What Are AI Agents? 关键词提示:本文将介绍 AI agents, knowledge graph, LangChain, Graphiti 等相关术语&am…...

8分钟快速掌握Markdiwn

文档说明:本文档适合有编程基础的专业人士快速学习Markdown语法,从而立即上手使用Markdown来记笔记,新手可移步至Markdown入门到精通实战教程:使用Typora快速构建编辑MD文档_md文件编辑器typora-CSDN博客 进行入门学习 Markdown文档的元素包括块级元素、内联元素、HTML元素…...

多维驱动:负载均衡何以成为现代系统架构的基石

负载均衡的引入是现代网络架构和分布式系统发展的必然需求,除了上述提到的原因,还涉及以下多个关键层面,共同推动其成为复杂系统不可或缺的组成部分: 一、提升服务质量(QoS) 响应时间优化:用户…...

本地知识库工具FASTGPT的安装与搭建

FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,将智能对话与可视化编排完美结合,让 AI 应用开发变得简单自然。无论您是开发者还是业务人员,都能轻松打造专属的 AI 应用。 今天来试着搭建下,使用docker安装比较简单&#x…...

【嘉立创EDA】如何找到曲线和直线的交点,或找到弧线和直线的交点

文章路标👉 :one: 文章解决问题:two: 主题内容:three: 参考方法be end..1️⃣ 文章解决问题 操作环境:嘉立创EDA专业版 V2.2.38 本文使用嘉立创EDA,描述如何快速找到曲线和直线交点的方法,这里的曲线包括了弧线等。本文将此过程记录,以供有需要的读者参考。 2️⃣ 主题…...

余额分账和代付有什么区别?

余额分账和代付有什么区别?余额分账是把钱存到一起,但代付是把钱分开。看似简单的一字之差,却有着本质的区别。 余额分账是一种财务管理手段,在一个账户或平台上,根据一定的规则将账户内的余额进行划分,形…...

【Stable Diffusion】文生图进阶指南:采样器、噪声调度与迭代步数的解析

在Stable Diffusion文生图(Text-to-Image)的创作过程中,采样器(Sampler)、噪声调度器(Schedule type)和采样迭代步数(Steps)是影响生成效果的核心参数。本文将从技术原理、参数优化到实践应用,深入剖析DPM++ 2M采样器、Automatic噪声调度器以及采样步数的设计逻辑与协…...

1.1探索 LLaMA-Factory:大模型微调的一站式解决方案

探索 LLaMA-Factory:大模型微调的一站式解决方案 引言 在大模型的时代,微调技术是将预训练模型适配到特定任务的关键。LLaMA-Factory 作为一款强大的工具,为开发者提供了便捷且高效的大模型微调解决方案。本文将深入介绍 LLaMA-Factory 的基…...

嵌入式开发面试常见编程题解析:pthread_join 与 pthread_detach 详解

一、引言 在多线程编程中,线程的资源管理至关重要。pthread_join 和 pthread_detach 是用于线程资源管理的两个重要函数。正确使用它们可以确保线程资源的合理回收,避免出现资源泄漏等问题。本文将详细介绍这两个函数的区别、使用方法、常见易错点以及拓…...

C#里嵌入lua脚本的例子

由于lua脚本比较小,并且适用性很强,非常适合嵌入式系统里加入。 比如在GD32的MCU里运行lua脚本,又者在ESP32里运行它,都是比较方便的。 当脚本要发送给MCU运行之前,我们需要在PC的软件里对脚本进行编译, 以便发现脚本有什么问题,不能在MCU里去发现问题,否则那样会比…...

git配置SSH KEY

1. 生成SSH密钥 ssh-keygen一直按回车 2.查看密钥 去.ssh目录查看生成的密钥文件 .pub结尾的文件即是密钥文件 3.配置SSH KEY 到代码仓库如GitHub,gitlab等配置SSH KEY,将密钥复制上去添加即可...

js day9

js当中与滚动相关的属性 <div>haha</div> <script>let boxdocument.querySelector("div")box.addEventListener("scoll",function(e)){console.log(window.scrolltop) }//往上走了 </script> ,box.scrollHeight——获取元素内容…...

【docker】启动临时MongoDB容器、挂载数据卷运行数据库服务,并通过备份文件恢复MongoDB数据库备份数据

‌启动临时 MongoDB 容器、挂载数据卷运行数据库服务&#xff0c;并通过备份文件恢复数据 1.命令分解与功能说明1.1.启动一个临时 MongoDB 容器‌&#xff0c;并进入交互式终端&#xff08;1&#xff09;执行命令&#xff08;2&#xff09;实现功能‌&#xff08;3&#xff09;…...

20_大模型微调和训练之-基于LLamaFactory+LoRA微调LLama3后格式合并

1. 什么是 GGUF GGUF 格式的全名为(GPT-Generated Unified Format)&#xff0c;提到 GGUF 就不得不提到它的前身 GGML(GPT-Generated Model Language)。GGML 是专门为了机器学习设计的张量库&#xff0c;最早可 以追溯到 2022/10。其目的是为了有一个单文件共享的格式&#xf…...

LLamaFactory如何在Windows系统下部署安装训练(保姆级教程)

注意&#xff1a;以下教程编写和灵感来源均来自eogee开源作者&#xff08;EOGEE_岳极技术_大模型与AI知识技术共享社区&#xff09;&#xff0c;大家有需要学习AI方面的知识可以关注他。 另我个人此次环境部署所用的显卡是5070ti16G显存&#xff0c;系统是Windows11。 如有问题…...

数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记7

前言 在前面文章的介绍中&#xff0c;已经介绍了数据定义、数据更新、数据查询&#xff0c;关于SQL语句的标准语言已经基本上介绍完毕&#xff0c;本文接下来将介绍另外两种便于操作的操作模式——视图与索引。其大致的语句代码与前文其实并无大的区别&#xff0c;在了解基本语…...

【LeetCode】彩灯装饰记录 III

题目 题目链接 一棵圣诞树记作根节点为 root 的二叉树&#xff0c;节点值为该位置装饰彩灯的颜色编号。请按照如下规则记录彩灯装饰结果&#xff1a; 第一层按照从左到右的顺序记录 除第一层外每一层的记录顺序均与上一层相反。即第一层为从左到右&#xff0c;第二层为从右到左…...

MongoDB的图形化工具robo3t,navicat

MongoDB 常用的两个图形化工具 —— Robo 3T 和 Navicat 的详细介绍、区别和基本使用方法&#xff1a; &#x1f9f0; 一、Robo 3T&#xff08;原 Robomongo&#xff09; &#x1f4cc; 简介 Robo 3T 是一款专注于 MongoDB 的轻量级可视化客户端。由原 Robomongo 团队开发&am…...

python celery框架结合django的使用

学习目标&#xff1a; 通过文章了解celery的运行机制以及如何结合django去使用 熟悉celery的运行原理属性celery在django项目当中的配置如何启动运行celery框架 学习内容&#xff1a; 熟悉celery的运行原理&#xff0c;简单来说 Celery 是一个“任务排队机后台处理器”。帮你…...

Ansible 守护 Windows 安全(Ansible Safeguards Windows Security)

Ansible 守护 Windows 安全&#xff1a;自动化基线检查与加固 在当今网络威胁日益严峻的形势下&#xff0c;保障 Windows 系统安全至关重要。Ansible 作为一款强大的自动化运维工具&#xff0c;可通过自动化脚本实现 Windows 安全基线检查和加固&#xff0c;大幅提升运维效率并…...

【计算机架构】CISC(复杂指令集计算机)架构

一、引言 在计算机技术领域中&#xff0c;计算机架构是基石&#xff0c;决定着计算机系统的性能、功能和效率。CISC&#xff08;复杂指令集计算机&#xff09;架构作为一种经典的计算机架构&#xff0c;自诞生以来就在计算机发展历程中扮演着举足轻重的角色。从早期的大型计算机…...

【学习资源】知识图谱与大语言模型融合

知识图谱与大型语言模型结合参数知识和明确知识的可用性会带来一些机会和愿景。分享一些知识图谱和大语言模型融合的论文和文章、实践案例、关键技术和实用工具。 1 模型库获取 https://modelscope.cn/models 注 下载模型需运行 git lfs instal 2 论文和文章 2.1 大型语言模…...

探索微服务入口:Spring Cloud Gateway 实战指南

在微服务架构中&#xff0c;网关&#xff08;Gateway&#xff09;扮演着“请求入口”的角色。它不仅帮助我们统一入口、路由转发&#xff0c;还可以承担限流、安全认证、权限校验、熔断等功能。 本文将系统介绍 Spring Cloud Gateway 的基础概念、快速上手指南&#xff0c;以及…...

python的turtle库实现四叶草

实现代码&#xff1a; import turtle turtle.pencolor(‘green’) turtle.fillcolor(‘green’) turtle.begin_fill() turtle.circle(100,90) turtle.left(90) turtle.circle(100,90) turtle.right(180) turtle.circle(100, 90) turtle.left(90) turtle.circle(100,90) tu…...

医疗生态全域智能化:从技术革新到价值重塑的深度探析

引言 医疗人工智能正在经历从单一技术应用向全域生态系统演进的关键转折点。随着深度学习、自然语言处理和计算机视觉等技术的成熟,AI不再局限于辅助诊断等单一功能,而是逐渐渗透到医疗健康服务的全生命周期。从传统设备制造商向智慧医疗转型的东软医疗,正在构建"AI大…...

Rust 的 Web 世界:actix_web 轻松接收 JSON 请求体

前言 在现代 Web 世界,数据传输早已从“你问我答”的问卷时代,迈入“你扔我接”的快节奏赛道。其中最火的“传球”方式,非 JSON 请求体莫属。Rust 这门以高性能和强类型著称的语言,也不甘人后,推出 actix_web 框架,力求在 Web 世界中杀出一条血路。 今天我们不讲玄学,…...

1.3 点云数据获取方式——ToF相机

图1-3-1TOF相机 ToF 相机作为新兴的 3D 感知设备,凭借独特的技术优势崭露头角。其工作原理基于光飞行时间(Time of Flight)技术,通过测量光信号从发射到被物体反射后返回传感器的时间差,直接且快速地获取物体的深度信息。这种直接测量深度的方式使得 ToF 相机具备…...

数据结构每日一题day13(链表)★★★★★

题目描述&#xff1a;采用尾插法在头指针L处建立一个带头结点的单链表,输入-1表示结束结果返回建立的单链表。 算法思想&#xff1a; 1.初始化链表&#xff1a;创建一个头结点&#xff08;不存储实际数据&#xff09;&#xff0c;头指针 L 指向该头结点。初始时&#xff0c;头…...

【网络编程】UDP协议 和 Socket编程

1. UDP的特点 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是互联网协议套件中的一种传输层协议&#xff0c;与广泛使用的TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;相比&#xff0c;它是一种无连接…...

【探寻C++之旅】第十二章:异常

请君浏览 前言1.异常的概念2.异常的使用2.1 抛出与捕获2.2 栈展开2.3 查找匹配的处理代码2.4 简单的异常使用2.5 异常重新抛出 2. 异常的安全问题3. 异常的规范4. 标准库的异常5. 异常处理建议尾声 前言 今天&#xff0c;我们继续踏入追寻C的冒险历程。今天我们让我们来讲讲C中…...

CSS的三大特性:层叠、继承与优先级

CSS作为网页设计的核心语言&#xff0c;其三大核心特性——层叠性、继承性和优先级共同构成了样式表现的底层逻辑。理解这些特性将帮助开发者写出更优雅、更易维护的样式代码。 一、层叠性&#xff08;Cascading&#xff09; 1.1 核心概念 "层叠"指多个样式规则同…...

Spring Cloud 项目中优雅地传递用户信息:基于 Gateway + ThreadLocal 的用户上下文方案

在 Spring Cloud 微服务架构中&#xff0c;我们通常使用 API 网关&#xff08;如 Spring Cloud Gateway&#xff09;作为流量入口&#xff0c;负责统一的用户身份校验和请求路由。本文将介绍一种通用的用户信息传递方案&#xff1a;网关完成认证后通过请求头传递用户信息&#…...

node.js 实战——mongoDB 续一

mongoDB的基本指令 进入mongodb mongo显示当前的所有数据库 show dbs # 或者 show databases切换数据库/进入指定数据库 使用这个命令的时候&#xff0c;是不要求这个数据库是否创建 use 数据库名显示当前数据库 db显示数据库中所有集合 show collections数据库的CRUD的…...

鸟笼效应——AI与思维模型【84】

一、定义 鸟笼效应思维模型指的是人们在偶然获得一件原本不需要的物品后,会为了这件物品的配套或使用需求,进而继续添加更多与之相关但自己原本可能并不需要的东西,仿佛被这个“鸟笼”牵着走,最终陷入一种惯性消费或行为模式的现象。简单来说,就是人们在心理上会有一种自…...

豪越科技消防立库方案:实现应急物资高效管理

在消防救援工作中&#xff0c;应急物资管理是至关重要的一环。然而&#xff0c;当前应急物资管理的现状却令人担忧。传统的应急物资管理方式存在诸多弊端&#xff0c;严重影响了消防救援的效率和效果。 走进一些传统的消防仓库&#xff0c;映入眼帘的往往是杂乱无章的存储场景。…...

简化excel校验提高开发效率

业务背景&#xff1a;上传excel文件进行基础数据校验&#xff0c;然而东西太多写着写着就...自然成了测试的KPI了 解决思路&#xff1a;使用现有的注解处理&#xff0c;原理使用validate注解原理 直接上干货&#xff0c;一行代码搞定校验&#xff1a; ValidateUtils.validat…...

ElasticSearch深入解析(六):集群核心配置

1.开发模式和生产模式 Elasticsearch默认运行在开发模式下&#xff0c;此模式允许节点在配置存在错误时照常启动&#xff0c;仅将警告信息写入日志文件。而生产模式则更为严格&#xff0c;一旦检测到配置错误&#xff0c;节点将无法启动&#xff0c;这是一种保障系统稳定性的安…...

Python 重构“策略”模式:用函数简化设计模式的实践

在软件设计中&#xff0c;设计模式是解决问题的通用模板。但随着编程语言特性的发展&#xff0c;某些经典模式可以通过更简洁的方式实现。本文以电商促销折扣场景为例&#xff0c;演示如何通过函数重构“策略”模式&#xff0c;减少代码量并提升可维护性。 经典策略模式实现 …...

​MCP协议深度解析:原理、应用与物联网时代的机遇-优雅草卓伊凡

MCP协议深度解析&#xff1a;原理、应用与物联网时代的机遇-优雅草卓伊凡 一、MCP协议技术详解 1.1 MCP协议的定义与起源 MCP&#xff08;Modbus Communication Protocol&#xff09;是一种基于主从架构的串行通信协议&#xff0c;最初由Modicon公司&#xff08;现为施耐德电…...

IOS 国际化词条 Python3 脚本

一、词条处理脚本---使用教程 (1)环境篇 1: 该脚本基于python3 环境&#xff0c;请确保你的mac 安装了python3 2: 包依赖&#xff0c;请在python3环境下安装 xlrd; pip3 install xlrd(2)使用篇 1: 桌面创建一个文件夹, 例如 wordEntry,将该脚本文件与下载的最新的 ’词条.xlsx‘…...

uniapp 支付宝小程序自定义 navbar 无效解决方案

如图&#xff1a; uniapp编译到支付宝小程序隐藏默认的导航栏失效了 解决方案&#xff1a; 在 pages.json 文件中找到 globalStyle 中加入以下代码&#xff1a; "mp-alipay": {"transparentTitle": "always","titlePenetrate":…...

uni-app - 微信小程序中,使用 navigateTo 传递非常大的数字传参精度丢失的问题

文章目录 🍉原因分析:JavaScript 数值精度限制🍉常用解决方法🍉代码示例🍉官方推荐与最佳实践🍉微信小程序环境注意事项🍉原因分析:JavaScript 数值精度限制 微信小程序(uni-app)中,参数是通过 URL 查询字符串传递的,其本质上仍由 JavaScript 进行处理。Jav…...

通信施工安全员B证适合哪些人考

通信施工安全员B证适合人群分析 一、适用岗位范围 通信工程施工人员 从事基站建设、光缆布放、管道施工等现场作业的技术工人 5G网络建设、室内分布系统安装等新型基础设施建设人员 项目管理岗位 通信工程项目经理、技术负责人 施工队长、班组长等现场管理人员 专职安全…...

vue3使用<el-date-picker分别设置开始时间和结束时间时,设置开始时间晚于当前时间,开始时间早于结束时间,结束时间晚于开始时间

vue3使用<el-date-picker分别设置开始时间和结束时间时&#xff0c;设置开始时间晚于当前时间&#xff0c;开始时间早于结束时间&#xff0c;结束时间晚于开始时间 为避免出现填写结束事件后再次修改开始时间&#xff0c;导致开始时间晚于结束时间&#xff0c;添加 change“…...

移远通信LG69T赋能零跑B10:高精度定位护航,共赴汽车智联未来

当前&#xff0c;汽车行业正以前所未有的速度迈向智能化时代&#xff0c;组合辅助驾驶技术已然成为车厂突出重围的关键所在。高精度定位技术作为实现车辆精准感知与高效协同的基石&#xff0c;其重要性日益凸显。 作为全球领先的物联网及车联网整体解决方案供应商&#xff0c;移…...

HTML应用指南:利用POST请求获取全国达美乐门店位置信息

达美乐比萨作为全球知名的披萨连锁品牌&#xff0c;自1960年创立以来&#xff0c;始终致力于为消费者提供高品质、快速配送的披萨体验。在中国市场&#xff0c;达美乐凭借其“30分钟必达”的承诺和经典美式风味&#xff0c;逐渐赢得了广大消费者的青睐。品牌通过不断拓展门店网…...