奇异值分解(SVD)时间复杂度分析与优化

奇异值分解是一种矩阵分解的方法,大学线性代数里面也讲过奇异值分解的方法,因此这是一个为大家所熟知的算法。

1 SVD 时间复杂度分析

给定一个 m × n m \times n m×n 的矩阵 a \boldsymbol{a} a,按照下面公式做分解,其中 Σ \Sigma Σ
是一个 m × n m \times n m×n 的矩阵,除对角线以为其他元素都是 0,对角线上的值就是所谓的奇异值。 U \boldsymbol{U} U 是 m × n m \times n m×n 的酉矩阵, V \boldsymbol{V} V 是 KaTeX parse error: Undefined control sequence: \n at position 1: \̲n̲ ̲\times n 的酉矩阵,即满足 U T ∗ U = I \boldsymbol{U} ^T * \boldsymbol{U} = \boldsymbol{I} UT∗U=I
A = U Σ V T \boldsymbol{A} = \boldsymbol{U} \boldsymbol{\Sigma} \boldsymbol{V} ^T A=UΣVT

  • 将 A \boldsymbol{A} A 的转置和 A \boldsymbol{A} A 做矩阵乘法,这样就会得到一个 n × n n \times n n×n 的方阵 A T ∗ A \boldsymbol{A} ^T ∗ \boldsymbol{A} AT∗A,然后运用方阵特征分解,得到 KaTeX parse error: Undefined control sequence: \fbf at position 64: …= \lambda _i ∗ \̲f̲b̲f̲{v} _i
  • 得到矩阵 A T ∗ A \boldsymbol{A} ^T ∗ \boldsymbol{A} AT∗A 的 n 个特征值和对应的 n 个特征向量 v \bf{v} v,将所有特征向量 v \bf{v} v 张成一个 KaTeX parse error: Undefined control sequence: \n at position 1: \̲n̲ ̲\times n 的矩阵 V \boldsymbol{V} V,就是前面公式里的 V \boldsymbol{V} V 矩阵,一般叫其中 V \boldsymbol{V} V 中的每个特征向量是 A \boldsymbol{A} A 的右奇异向量。
  • 同样的对 A \boldsymbol{A} A 和 A \boldsymbol{A} A 的转置做乘法,就得到 KaTeX parse error: Undefined control sequence: \m at position 1: \̲m̲ ̲\times m 的方阵 A ∗ A T \boldsymbol{A} ∗ \boldsymbol{A} ^T A∗AT,运用方阵特征分解,得到 A ∗ A T ∗ u i = λ i ∗ u i \boldsymbol{A} ∗ \boldsymbol{A} ^T * \bf{u} _i = \lambda _i * \bf{u} _i A∗AT∗ui​=λi​∗ui​
  • 得到矩阵 A ∗ A T \boldsymbol{A} ∗ \boldsymbol{A} ^T A∗AT 的 m 个特征值和对应的 m 个特征向量 u \bf{u} u,将所有特征向量 u \bf{u} u 张成一个 KaTeX parse error: Undefined control sequence: \m at position 1: \̲m̲ ̲\times m 的矩阵 U \boldsymbol{U} U,就是前面公式里的 U \boldsymbol{U} U 矩阵,一般叫 U \boldsymbol{U} U 中的每个特征向量是 A \boldsymbol{A} A 的左奇异向量。
  • 计算奇异矩阵 Σ \Sigma Σ
    A = U ∗ Σ ∗ V T ⇒ A ∗ U = U ∗ Σ ∗ V T ∗ V ⇒ A ∗ V = U ∗ Σ ⇒ A ∗ v i = σ i ∗ u i ⇒ σ i = A ∗ v i / u i \boldsymbol{A} = \boldsymbol{U} ∗ \boldsymbol{\Sigma} ∗ \boldsymbol{V} ^T \Rightarrow \boldsymbol{A} ∗ \boldsymbol{U} = \boldsymbol{U} ∗ \boldsymbol{\Sigma} ∗ \boldsymbol{V} ^T ∗ \boldsymbol{V} \Rightarrow \boldsymbol{A} ∗ \boldsymbol{V} = \boldsymbol{U} ∗ \boldsymbol{\Sigma} \Rightarrow \boldsymbol{A} ∗ \bf{v} _i = \bf{\sigma} _i ∗ \bf{u} _i \Rightarrow \bf{\sigma} _i = \boldsymbol{A} ∗ \bf{v} _i / \bf{u} _i A=U∗Σ∗VT⇒A∗U=U∗Σ∗VT∗V⇒A∗V=U∗Σ⇒A∗vi​=σi​∗ui​⇒σi​=A∗vi​/ui​

这样得到奇异值 σ \sigma σ, 组成奇异值矩阵 Σ \Sigma Σ。

这是标准的按照线性代数理论进行分解的方法。由于矩阵乘法的实时间复杂度是 O ( n 3 ) O(n^3) O(n3),那么不难得知,按照线性代数理论进行奇异值分解的时间复杂度是 O ( max ⁡ ( m , n ) 3 ) O(\max(m, n)^3) O(max(m,n)3)。

SVD 在工业上通常用于推荐系统,物料数和用户数通常最少也是千万级别,三次方下来就10,0000亿,一个很恐怖的时间复杂度,接下来介绍一个 SVD 的性质,然后继续分析怎么优化这个算法。

2 SVD 分解算法优化

2.1 奇异值分解性质

对于奇异值分解结果的中间矩阵,它对角线上的值称为奇异值,按照从大到小排序,并且奇异值下降特别快,正常情况下前10%的奇异值占有了全部奇异值的99%,那么可以用前 k 个奇异值近似表示原始矩阵。
A m × N = U m × m ∗ Σ m × n ∗ V n × n T ≈ U m × k ∗ Σ k × k ∗ V k × n T \boldsymbol{A} _{m \times N} = \boldsymbol{U} _{m \times m} * \Sigma _{m \times n} * \boldsymbol{V} _{n \times n} ^T \approx \boldsymbol{U} _{m \times k} * \Sigma _{k \times k} * \boldsymbol{V} _{k \times n} ^T Am×N​=Um×m​∗Σm×n​∗Vn×nT​≈Um×k​∗Σk×k​∗Vk×nT​
一般来说,这里 k < < min ⁡ ( m , n ) k << \min(m,n) k<<min(m,n),可以达到数据压缩或者降维的作用。

2.2 截断奇异值分解

利用上面提到的奇异值分解的性质,可以借助截断奇异值分解来优化奇异值分解。

首先不直接分解矩阵,而是用机器学习的方法,直接去求第二个矩阵。定义损失函数
C = ∑ ( i , j ) ∈ R [ ( a ( i j ) − u i ∗ v j T ) 2 + λ ( u i 2 + v j 2 ) ] \boldsymbol{C} = \sum _{(i, j) \in \boldsymbol{R}} [(\bf{a}_(ij) - \bf{u} _i * \bf{v} _j ^T)^2 + \lambda (\bf{u} _i ^2 + \bf{v}_j ^2)] C=(i,j)∈R∑​[(a(​ij)−ui​∗vjT​)2+λ(ui2​+vj2​)]

第一项使用平方差定义分解后和原始矩阵的 RMSE,其中 b f a i j bf{a}_{ij} bfaij​ 是原始矩阵的第 i 行第 j 列, u i \bf{u} _i ui​ 是推荐系统场景中的用户特征向量, v j \bf{v} _j vj​ 是物品特征向量,后面一项是正则化项。

有了损失函数就可以用 ALS 或者梯度下降法求解了。这里的时间复杂度是 O ( m n k ) O(mnk) O(mnk),而 k 是个很小的数,那么复杂度就是相当于是 O ( m ∗ n ) O(m*n) O(m∗n),这样在千万的数据上计算复杂度瞬间变成100亿了。

另外,在算法实现上,还可以使用并行计算的方式来进行 SVD 分解计算,限于篇幅这里暂时不做展开,Mars算法实践

3 变种 SVD 算法

3.1 改进的 SVD 算法

前面说到,奇异值分解常用在推荐系统中,最简单的方法就是直接把评分矩阵分解去做推荐,但是实际中发现不管是用户还是物品都存在一定偏差,比如有些用户给的评分就是比其他人高0.5,或者有些电影用户倾向于给高分,但是建模的时候没有考虑进去这种情况。那么把用户和物品的偏差考虑进来,那么就可以对 SVD 算法进行改进,评分 = 兴趣 + 偏见。

a u , i = u + b u + b i + U u ∗ V i T \bf{a} _{u, i} = \bf{u} + \bf{b}_u + \bf{b}_i + \boldsymbol{U}_u * \boldsymbol{V}_i^T au,i​=u+bu​+bi​+Uu​∗ViT​

其中 b u \bf{b}_u bu​ 表示用户偏见, b i \bf{b}_i bi​ 表示物品偏见, u \bf{u} u 表示全局均值,损失函数为:

C = ∑ ( u , i ) ∈ R ( a u , i − b i − b u − U u ∗ V i T ) 2 + λ ( ∣ ∣ U u ∣ ∣ 2 + ∣ ∣ V i ∣ ∣ 2 + b u 2 b i 2 ) \boldsymbol{C} = \sum _{(u, i) \in \boldsymbol{R}} \left( \bf{a}_{u, i} - \bf{b}_i - \bf{b}_u - \boldsymbol{U}_u * \boldsymbol{V}_i^T \right) ^2 + \lambda \left( ||\boldsymbol{U}_u|| ^2 + ||\boldsymbol{V}_i|| ^2 + \bf{b}_u ^2 \bf{b}_i ^2 \right) C=(u,i)∈R∑​(au,i​−bi​−bu​−Uu​∗ViT​)2+λ(∣∣Uu​∣∣2+∣∣Vi​∣∣2+bu2​bi2​)

3.2 SVD++ 算法

实际使用中,除了用户或者物品偏见,还有一个问题就是行为数据中的评分数据很少,但是隐式行为数据有很多,把隐式行为数据建模进去从而缓解评分稀疏提高推荐效果,这就是 SVD++ 算法。SVD++ 在 SVD 中加入了用户对物品的隐式行为,SVD++ 的假设条件是评分 = 显式兴趣 + 隐式兴趣 + 偏见

a u , i = u + b u + b i + V i T ∗ ( U u + ∣ I u ∣ − 1 2 ∗ ∑ j ∈ I u y j ) \bf{a} _{u, i} = \bf{u} + \bf{b}_u + \bf{b}_i + \boldsymbol{V}_i^T * \left( \boldsymbol{U}_u + |\boldsymbol{I}_u| ^{-\frac{1}{2}} * \sum _{j \in \boldsymbol{I} _u} y_j \right) au,i​=u+bu​+bi​+ViT​∗ ​Uu​+∣Iu​∣−21​∗j∈Iu​∑​yj​ ​

其中 I u \boldsymbol{I} _u Iu​ 是该用户有隐式行为的所有物品集合,而 y j y_j yj​ 是隐式评分电影 j 反应出的喜好值,其中对 I u \boldsymbol{I} _u Iu​ 取根号是一个经验值,这样就把系统中大量的隐式行为也建模到 SVD 算法中,虽然这么做对计算复杂度提高了不少,但是能够缓解评分稀疏提高推荐效果。同样的,损失函数为:

C = ∑ ( u , i ) ∈ R ( a u , i − b i − b u − V i T ∗ ( U u + min ⁡ ( ∣ I u ∣ − 1 2 ∗ ∑ j ∈ I u y j ) ) ) 2 + λ ( ∑ u ( b i , u 2 + ∣ ∣ U u ∣ ∣ 2 ) + ∑ i ( b i 2 + ∣ ∣ V i ∣ ∣ 2 + ∣ ∣ y i ∣ ∣ 2 ) ) \boldsymbol{C} = \sum _{(u, i) \in \boldsymbol{R}} \left( \bf{a}_{u, i} - \bf{b}_i - \bf{b}_u - \boldsymbol{V}_i^T * (\boldsymbol{U}_u + \min(|\boldsymbol{I}_u| ^{-\frac{1}{2}} * \sum _{j \in \boldsymbol{I} _u} y_j)) \right) ^2 + \lambda \left( \sum _u (\bf{b}_{i, u}^2 + ||\boldsymbol{U} _u||^2) + \sum _i (\bf{b}_i^2 + ||\boldsymbol{V}_i|| ^2 + ||\bf{y}_i||^2) \right) C=(u,i)∈R∑​ ​au,i​−bi​−bu​−ViT​∗(Uu​+min(∣Iu​∣−21​∗j∈Iu​∑​yj​)) ​2+λ(u∑​(bi,u2​+∣∣Uu​∣∣2)+i∑​(bi2​+∣∣Vi​∣∣2+∣∣yi​∣∣2))

3.3 timeSVD 算法

2010 年,Koren 发现在 Netflix 的数据中,个体用户的兴趣会随着时间转移,论文中称作 concepte drift (观念转移)。比如大家都知道的《大话西游》,刚上映票房很低,大家都给出的评分也不高,但是随着时间流逝,大家给出的评分越来越高。另外可能有些电影在某些特定的节日或者某天会获得高分,作者希望建立模型能捕捉到这些。

timeSVD 在 SVD 中加入了时间因素,也可以叫做有时序的SVD。timeSVD 的假设条件是评分 = 显式兴趣 + 时序兴趣 + 热点 + 偏见

按照原始论文的介绍来说,这个模型是为了对观念转移建模。从三个角度出发,首先是时间窗口概念,另外是实例权重,采用时间衰减,最后是集成学习的概念,引入多个基础预估方法。

static predictor 是最基础的预估方法:
b u , i ( t ) = u + b u + b i \bf{b}_{u,i}(t) = \bf{u} + \bf{b}_u + \bf{b}_i bu,i​(t)=u+bu​+bi​
mov方案 mov predictor:
b u , i ( t ) = u + b u + b i + b i , B i n ( t ) \bf{b}_{u,i}(t) = \bf{u} + \bf{b}_u + \bf{b}_i + \bf{b}_{i, Bin(t)} bu,i​(t)=u+bu​+bi​+bi,Bin(t)​

这里对 b i \bf{b}_i bi​ 是 b i ( t ) = b f b i + b i , B i n ( t ) \bf{b}_i(t) = bf{b}_i + \bf{b}_{i, Bin(t)} bi​(t)=bfbi​+bi,Bin(t)​,分为Static和time changing两部分,引入物品的时间变化因素,对时间片进行划分。论文中是以10周为一片,共划分了30片,赋予一个 B i n ( t ) Bin(t) Bin(t),即1-30之间。时间片划分也可以是其他的,小的时间片可以有更好的性能,大的时间片能够让每片有更多的数据。

linear predictor,引入用户兴趣的变化,首先定义
d e v u ( t ) = s i g n ( t − t u ) ∗ ∣ t − t u ∣ β dev_u(t) = sign(t - t_u)*|t - t_u|^{\beta} devu​(t)=sign(t−tu​)∗∣t−tu​∣β
表示当前用户当前评分时间和平均评分时间的距离,论文中 β = 0.4 β=0.4 β=0.4

然后对 b u \bf{b}_u bu​ 引入时间变化到线性模型,多了一个需要训练的参数 α \alpha α
b u ( 1 ) = b f b u + α u ∗ d e v u ( t ) \bf{b}_u^{(1)} = bf{b}_u + \alpha _u * dev_u(t) bu(1)​=bfbu​+αu​∗devu​(t)
引入到公式中得到
b u , i ( t ) = u + b u + α u ∗ d e v u ( t ) + b i + b i , B i n ( t ) \bf{b}_{u, i}(t) = \bf{u} + \bf{b}_u + \alpha _u * dev_u(t) + \bf{b}_i + \bf{b}_{i, Bin(t)} bu,i​(t)=u+bu​+αu​∗devu​(t)+bi​+bi,Bin(t)​

spline predictor 通过另一种方法引入用户兴趣变化的模型,区别于前面的线性模型,这是一个曲线式模型
b u , i ( t ) = u + b u + ∑ l = 1 k u e − r ∣ t − t u ∣ ∗ b t , l u ∑ l = 1 k u e − r ∣ t − t u ∣ + b i + b i , B i n ( t ) \bf{b}_{u, i}(t) = \bf{u} + \bf{b}_u + \frac{\sum _{l=1} ^{k_u} e^{-r|t-t^u|} * \bf{b}_{t, l}^{u}}{\sum _{l=1} ^{k_u} e^{-r|t-t^u|}} + \bf{b}_i + \bf{b}_{i, Bin(t)} bu,i​(t)=u+bu​+∑l=1ku​​e−r∣t−tu∣∑l=1ku​​e−r∣t−tu∣∗bt,lu​​+bi​+bi,Bin(t)​

linear+ predictor 引入实时特定,比如用户某天心情,或者生日等,引入一个参数 b u , t \bf{b}_{u, t} bu,t​,表示每日的特定偏差
b u , i ( t ) = u + b u + α u ∗ d e v u ( t ) + b i + b u , t + b i , B i n ( t ) \bf{b}_{u, i}(t) = \bf{u} + \bf{b}_u + \alpha _u * dev_u(t) + \bf{b}_i + \bf{b}_{u, t} + \bf{b}_{i, Bin(t)} bu,i​(t)=u+bu​+αu​∗devu​(t)+bi​+bu,t​+bi,Bin(t)​

spline+ predictor 曲线模型也引入,
b u , i ( t ) = u + b u + ∑ l = 1 k u e − r ∣ t − t u ∣ ∗ b t , l u ∑ l = 1 k u e − r ∣ t − t u ∣ + b i + b u , t + b i , B i n ( t ) \bf{b}_{u, i}(t) = \bf{u} + \bf{b}_u + \frac{\sum _{l=1} ^{k_u} e^{-r|t-t^u|} * \bf{b}_{t, l}^{u}}{\sum _{l=1} ^{k_u} e^{-r|t-t^u|}} + \bf{b}_i + \bf{b}_{u, t} + \bf{b}_{i, Bin(t)} bu,i​(t)=u+bu​+∑l=1ku​​e−r∣t−tu∣∑l=1ku​​e−r∣t−tu∣∗bt,lu​​+bi​+bu,t​+bi,Bin(t)​

通过梯度下降法进行训练,损失函数为
C = ∑ u , i , t ∈ K ( r u , i ( t ) − u − b u − α u ∗ d e v u ( t ) − b i − b u , t − b i , B i n ( t ) ) 2 + λ ∗ ( b u 2 + α u 2 + b u , t 2 + b i 2 + b i , B i n t 2 ) \boldsymbol{C} = \sum _{u, i, t \in \boldsymbol{K}} \left( \bf{r}_{u, i}(t) - \bf{u} - \bf{b}_u - \alpha _u * dev_u(t) - \bf{b}_i - \bf{b}_{u, t} - \bf{b}_{i, Bin(t)} \right) ^2 + \lambda * \left(\bf{b}_u^2 + \bf{\alpha}_u^2 + \bf{b}_{u, t}^2 + \bf{b}_i^2 + \bf{b}_{i, Bin{t}}^2 \right) C=u,i,t∈K∑​(ru,i​(t)−u−bu​−αu​∗devu​(t)−bi​−bu,t​−bi,Bin(t)​)2+λ∗(bu2​+αu2​+bu,t2​+bi2​+bi,Bint2​)
原论文中对各个 predictor 用 RMSE 作为指标的结果
在这里插入图片描述

这里通过时序建模,用户矩阵的参数表示为:
u u ( t ) [ k ] = p u , k + α u , k ∗ d e v u ( t ) + p u , k ∗ k = 1 , ⋯ , f \bf{u}_u(t)[k] = \bf{p}_{u, k} + \bf{\alpha}_{u, k} * dev_u(t) + \bf{p}_{u, k} * \bf{k} = 1, \cdots, f uu​(t)[k]=pu,k​+αu,k​∗devu​(t)+pu,k​∗k=1,⋯,f
这里 k 代表第 k 个 predictor,每一个 predictor 单独训练,最终得到如下公式,
a u , i = u + b i ( t ) + b u ( t ) + V i T ∗ ( u u ( t ) + ∣ I u ∣ − 1 2 ∗ ∑ j ∈ I u y j ) \bf{a}_{u, i} = \bf{u} + \bf{b}_i(t) + \bf{b}_u(t) + \boldsymbol{V}_i^T * (\bf{u}_u(t) + |\boldsymbol{I}_u|^{-\frac{1}{2}} * \sum _{j \in \boldsymbol{I}_u} y_j) au,i​=u+bi​(t)+bu​(t)+ViT​∗(uu​(t)+∣Iu​∣−21​∗j∈Iu​∑​yj​)
通过在 Netflix 数据集测试,对比三种算法,可以得到
在这里插入图片描述

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

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

相关文章

mysql插入之前先测试环境试试

在生产环境中直接执行数据库操作可能会引起一系列问题&#xff0c;比如性能下降、数据不一致甚至系统崩溃。因此&#xff0c;在实际操作前在测试环境中进行彻底的测试非常重要。 测试环境准备&#xff1a; 确保测试环境与生产环境尽可能一致。这包括硬件配置、网络设置、数据库…

Java+TestNG

TestNG是Java中的一个测试框架&#xff0c;主要用于编写和执行自动化测试用例。它是一个功能强大的测试工具&#xff0c;旨在提供一个比JUnit更强大、更灵活的测试框架。TestNG的设计目标是简化广泛的测试需求&#xff0c;从单元测试&#xff08;隔离测试一个类&#xff09;到集…

福派斯牛肉高脂猫粮,为何成猫舍首选?揭秘其神奇功效!

&#x1f43e; 说到猫咪的伙食&#xff0c;咱们当铲屎官的可是操碎了心&#xff01;想让自家毛孩子吃得健康又开心&#xff0c;选对猫粮真的太重要了。今天就来聊聊为啥福派斯牛肉高脂猫粮能成为众多猫舍的首选&#xff0c;以及它到底能帮咱们的小猫咪哪些忙吧&#xff01; 1️…

mybatis查询数据字段返回空值

1.描述 数据苦衷实际存储字段全不为空 查询后brand_name/company_name为空 2.原因分析 带下划线的字段&#xff0c;都会返回空值&#xff0c;应该是字段映射出了问题 3.解决方案 在配置文件中添加下划线自动映射为驼峰 <configuration><settings><sett…

编写Dockerfile文件解释

编写Dockerfile文件的基本步骤如下&#xff1a; 首先&#xff0c;创建一个新的文本文件&#xff0c;并将其命名为Dockerfile。 在Dockerfile的第一行添加基础镜像的指令。例如&#xff0c;使用ubuntu 18.04作为基础镜像&#xff0c;可以添加以下指令&#xff1a; FROM ubunt…

电子档案系统与双层PDF及基于Elasticsearch全文检索技术的探索

随着信息化时代的到来&#xff0c;电子档案系统作为信息资源管理的重要工具&#xff0c;其发展和应用受到了广泛关注。本文旨在探讨电子档案系统中扫描件的数字化处理、双层PDF的构建及其优势&#xff0c;并详细阐述了全文检索技术在电子档案管理中的应用&#xff0c;特别是基于…

鸿蒙开发——axios封装请求、拦截器

描述&#xff1a;接口用的是PHP&#xff0c;框架TP5 源码地址 链接&#xff1a;https://pan.quark.cn/s/a610610ca406 提取码&#xff1a;rbYX 请求登录 HttpUtil HttpApi 使用方法

LangChain结合LLM做RAG文档搜索

我们知道LLM&#xff08;大语言模型&#xff09;的底模是基于已经过期的公开数据训练出来的&#xff0c;对于新的知识或者私有化的数据LLM一般无法作答&#xff0c;此时LLM会出现“幻觉”。针对“幻觉”问题&#xff0c;一般的解决方案是采用RAG做检索增强。 但是我们不可能把…

十、Docker版Redis集群搭建

目录 一、3主3从Redis集群配置 1、新建6个docker容器实例 2、进入容器redis-node-1并为6台机器构建集群关系 3、以6381为切入点,查看集群状态 二、主从容错切换迁移案例 1、数据读写存储 2、假如6381宕机了,他的从库6386会不会切换 三、主从扩容案例 1、新建6387、63…

SQL 基础知识

SQL&#xff08;结构化查询语言&#xff09;是一种用于管理和操作关系数据库的标准编程语言。以下是一些 SQL 的基础知识&#xff1a; 基本概念 数据库&#xff08;Database&#xff09;&#xff1a; 存储和管理数据的容器。一个数据库可以包含多个表。 表&#xff08;Table&…

C语言 | Leetcode C语言题解之第292题Nim游戏

题目&#xff1a; 题解&#xff1a; bool canWinNim(int n) {return n % 4 ! 0; }

C语言模块化编程技术详解

C语言模块化编程技术详解&#xff08;第一部分&#xff09; 模块化编程是一种将程序划分为多个模块的编程方法&#xff0c;每个模块负责完成特定的功能。在C语言中&#xff0c;模块化编程可以提高代码的可读性、可维护性和可重用性。本文将深入探讨C语言模块化编程的工作原理&…

【Linux】文件系统|CHS寻址|LBA逻辑块|文件索引|inode|Date block|inodeBitmap|blockBitmap

前言 一个进程通过文件描述符标识一个打开的文件&#xff0c;进程拿着文件描述符可以在内核中找到目标文件进行读写等操作。这是打开的文件&#xff0c;而没有被打开的文件存储在磁盘中&#xff0c;是如何管理的&#xff1f;操作系统在偌大的磁盘中如何找到想要的文件并打开的…

在CentOS 7上安装Apache Tomcat 10.0.27

要在CentOS 7上安装Apache Tomcat 10.0.27&#xff0c;可以按照以下步骤操作&#xff1a; 安装Java开发工具包 (JDK): Tomcat需要Java环境。可以使用以下命令安装OpenJDK 11&#xff1a; sudo yum install java-11-openjdk-devel下载Tomcat 10.0.27: 从Tomcat官方网站下载Tomca…

凸优化笔记-基本概念

原文 文章目录 最小二乘问题 仿射affine hullaffine dimension 凸集锥集超平面和半空间单纯形整半定锥保凸性的操作透视函数 凸函数的条件1阶判定条件2阶判定条件 Epigraph 外图 m i n i m i z e f 0 ( x ) minimize\ \ \ f_0(x) minimize f0​(x) s u b j e c t t o f i ( …

Leetcode32-求出出现两次数字的 XOR 值(3158)

1、题目 给你一个数组 nums &#xff0c;数组中的数字 要么 出现一次&#xff0c;要么 出现两次。 请你返回数组中所有出现两次数字的按位 XOR 值&#xff0c;如果没有数字出现过两次&#xff0c;返回 0 。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,1,3] 输出&…

C#实现数据采集系统-Tcp粘包处理

Tcp通信中会出现粘包的情况,Tcp数据不是完全一收一发,而是会将接收到数据存在一个接收缓冲区,等到调用接收的把数据从缓冲区取出来 大部分时候,我们收发消息频率不高,看上去就是发一条,收一条,完整数据;理论上,接收一次,是会出现各种情况, 粘包的几种情况 接收不完…

Spring Boot入门指南:留言板

一.留言板 1.输⼊留⾔信息,点击提交.后端把数据存储起来. 2.⻚⾯展⽰输⼊的表⽩墙的信息 规范&#xff1a; 1.写一个类MessageInfo对象&#xff0c;添加构造方法 虽然有快捷键&#xff0c;但是还是不够偷懒 项目添加Lombok。 Lombok是⼀个Java⼯具库&#xff0c;通过添加注…

Java从基础到高级特性及应用

Java&#xff0c;作为一门历史悠久且广泛应用的编程语言&#xff0c;自1995年问世以来&#xff0c;便以其跨平台性、面向对象、自动内存管理等特点&#xff0c;在软件开发领域占据了举足轻重的地位。从桌面应用到企业级系统&#xff0c;从移动开发到云计算服务&#xff0c;Java…

Spring Boot 与 MongoDB 整合指南

MongoDB MongoDB 是一种基于文档的NoSQL数据库&#xff0c;以其高性能、高可用性和易扩展性而著称。它使用 BSON&#xff08;类似 JSON 的二进制格式&#xff09;来存储数据&#xff0c;提供了灵活的数据模型&#xff0c;使得开发者可以更轻松地存储和查询复杂的数据结构。将M…