聚类算法之谱聚类

article/2025/10/9 2:21:42

谱聚类

1. 基本原理

它的主要思想:把所有数据看成空间中的点,这些点之间可以用变连接起来,距离较远的两个点之间的边权重较低,而距离较近的两个点之间的权重较高,通过对所有数据点组成的图进行切图,让切图后的不同的子图间边权重和尽可能小(即距离远),而子图内的边权重和尽可能高(即距离近)。

难点:

  1. 如何构建图?
  2. 如何切分图?

2. 谱聚类基础

2.1 无向权重图

对于一个图 G G G,我们一般用点集合 V = { v 1 , v 2 , . . . . , v n } V=\{v_1,v_2,....,v_n\} V={v1,v2,....,vn}和边集合 E E E来描述,即 G = ( V , E ) G=(V,E) G=(V,E)。我们定义权重 w i j w_{ij} wij为点 v i , v j v_i,v_j vi,vj之间的权重,由于是无向图,故 w i j = w j i w_{ij}=w_{ji} wij=wji

对于有边连接的两个点 v i 和 v j v_i和v_j vivj w i j > 0 w_{ij} > 0 wij>0;对于没有边连接的两个点 v i 和 v j v_i和v_j vivj w i j = 0 w_{ij} = 0 wij=0

对于图中的任意一个点 v i v_i vi,它的度 d i d_i di定义为和它相连的所有边权重之和,即
d i = ∑ j = 1 n w i j d_i=\sum_{j=1}^nw_{ij} di=j=1nwij

利用每个点度的定义,我们可以得到一个 n × n n \times n n×n的度矩阵 D D D,它是一个对角阵,只有主对角有值,对应第 i i i行为第 i i i个点的度;利用所有点之间的权重,我们可以得到图的邻接矩阵 W W W,它也是一个 n × n n \times n n×n矩阵,第 i i i行的第 j j j个值对应权重 w i j w_{ij} wij

除此之外,对于点集 V V V的一个子集 A ⊂ V A \subset V AV,我们定义:
∣ A ∣ : = 子 集 A 中 点 的 个 数 v o l ( A ) : = ∑ i ∈ A d i |A|:=子集A中点的个数 \\ vol(A):=\sum_{i \in A}d_i A:=Avol(A):=iAdi

2.2 拉普拉斯矩阵

拉普拉斯矩阵 L = D − W L=D-W L=DW,其性质如下:

  1. 对称矩阵,由于 D 和 W D和W DW都为对称矩阵
  2. 由于是对称矩阵,它的所有特征值都是实数
  3. 对于任意向量 f f f,有
    f T L f = f T D f − f T W f = ∑ i = 1 n d i f i 2 − ∑ i , j = 1 n w i j f i f j = 1 2 ( ∑ i = 1 n d i f i 2 − 2 ∑ i , j = 1 n w i j f i f j + ∑ j = 1 n d j f j 2 ) = 1 2 ∑ i , j = 1 n w i j ( f i − f j ) 2 f^TLf=f^TDf-f^TWf=\sum_{i=1}^nd_if_i^2-\sum_{i,j=1}^nw_{ij}f_if_j\\=\frac {1} {2}(\sum_{i=1}^nd_if_i^2-2\sum_{i,j=1}^nw_{ij}f_if_j+\sum_{j=1}^nd_jf_j^2)=\frac {1} {2}\sum_{i,j=1}^nw_{ij}(f_i-f_j)^2 fTLf=fTDffTWf=i=1ndifi2i,j=1nwijfifj=21(i=1ndifi22i,j=1nwijfifj+j=1ndjfj2)=21i,j=1nwij(fifj)2
  4. 由于拉普拉斯矩阵是半正定的,其对应的 n n n个特征值都大于等于0。

3. 构建图——构建邻接矩阵

3.1 ϵ \epsilon ϵ邻近法

通过设置一个阈值 ϵ \epsilon ϵ,然后利用欧氏距离 s i j s_{ij} sij度量任意两点 v i 和 v j v_i和v_j vivj的距离,即 s i j = ∣ ∣ v i − v j ∣ ∣ 2 2 s_{ij}=||v_i-v_j||_2^2 sij=vivj22,然后根据 s i j 和 ϵ s_{ij}和\epsilon sijϵ的大小关系,来定义邻接矩阵 W W W
w i j = { 0 , s i j > ϵ ϵ , s i j ≤ ϵ w_{ij}= \begin{cases} 0, \quad & s_{ij} >\epsilon \\ \epsilon, \quad & s_{ij} \leq \epsilon \end{cases} wij={0,ϵ,sij>ϵsijϵ

从上式可知,两点间的权重要么 ϵ \epsilon ϵ,要么0,就没有其他信息了,距离远近度量很不明确,因此在实际应用中,很少采用。

3.2 k k k近邻法

利用KNN算法遍历所有的样本点,取每个样本最近的 k k k个点作为近邻,只有和样本距离最近的 k k k个点之间的 w i j > 0 w_{ij}>0 wij>0。但是这种方法会造成重构之后的邻接矩阵 W W W非对称,我们后面的算法需要邻接矩阵对称。为了解决这种问题,一般采取下面两种方法之一:

  1. 只要一个点在另一个点的K近邻中,就保留 w i j w_{ij} wij
    w i j = w j i = { 0 v i ∉ K N N ( v j ) a n d v j ∉ K N N ( v i ) e x p ( − ∣ ∣ v i − x j ∣ ∣ 2 2 2 σ 2 ) v i ∈ K N N ( v j ) o r v j ∈ K N N ( v i ) w_{ij}=w_{ji}= \begin{cases} 0 & v_i \notin KNN(v_j) \quad and \quad v_j \notin KNN(v_i) \\ exp(-\frac {||v_i-x_j||_2^2} {2\sigma^2}) & v_i \in KNN(v_j) \quad or \quad v_j \in KNN(v_i) \end{cases} wij=wji={0exp(2σ2vixj22)vi/KNN(vj)andvj/KNN(vi)viKNN(vj)orvjKNN(vi)
  2. 必须两个点互为 K K K近邻中,才能保留 w i j w_{ij} wij
    w i j = w j i = { 0 v i ∉ K N N ( v j ) o r v j ∉ K N N ( v i ) e x p ( − ∣ ∣ v i − x j ∣ ∣ 2 2 2 σ 2 ) v i ∈ K N N ( v j ) a n d v j ∈ K N N ( v i ) w_{ij}=w_{ji}= \begin{cases} 0 & v_i \notin KNN(v_j) \quad or \quad v_j \notin KNN(v_i) \\ exp(-\frac {||v_i-x_j||_2^2} {2\sigma^2}) & v_i \in KNN(v_j) \quad and \quad v_j \in KNN(v_i) \end{cases} wij=wji={0exp(2σ2vixj22)vi/KNN(vj)orvj/KNN(vi)viKNN(vj)andvjKNN(vi)

3.3 全连接法

比前两种方法,第三种方法所有的点之间的权重值都大于0,因此称之为全连接法。可以选择不同的核函数来定义边权重,常用的有多项式核函数,高斯核函数和Sigmoid核函数。最常用的是高斯核函数RBF
w i j = e x p ( − ∣ ∣ v i − v j ∣ ∣ 2 2 2 σ 2 ) w_{ij}=exp(-\frac {||v_i-v_j||_2^2} {2\sigma^2}) wij=exp(2σ2vivj22)

在实际的应用中,使用第三种全连接法来建立邻接矩阵是最普遍的,而在全连接法中使用高斯径向核RBF是最普遍的。

4. 图的切分

对于无向图 G G G的切分,我们的目标是将图 G ( V , E ) G(V,E) G(V,E)切成相互没有连接的 k k k个子图,每个子图集合为: A 1 , A 2 , . . . , A k A_1,A_2,...,A_k A1,A2,...,Ak,它们满足 A i ∩ A j = ∅ 且 A 1 ∪ A 2 ∪ . . . ∪ A k = V A_i \cap A_j=\varnothing 且 A_1 \cup A_2 \cup ...\cup A_k=V AiAj=A1A2...Ak=V

对于任意两个子图点的集合 A , B ⊂ V , A ∩ B = ∅ A,B \subset V, A \cap B=\varnothing A,BV,AB=,我们定义 A 和 B A和B AB之间的切图权重为:
W ( A , B ) = ∑ i ∈ A , j ∈ B w i j W(A,B)=\sum_{i\in A,j\in B}w_{ij} W(A,B)=iA,jBwij
那么对于我们 k k k个子图点的集合: A 1 , A 2 , . . . , A k A_1,A_2,...,A_k A1,A2,...,Ak,我们定义切图 c u t cut cut为:
c u t ( A 1 , A 2 , . . . , A k ) = 1 2 ∑ i = 1 k W ( A i , A ˉ i ) cut(A_1,A_2,...,A_k)=\frac {1} {2}\sum_{i=1}^kW(A_i, \bar A_i) cut(A1,A2,...,Ak)=21i=1kW(Ai,Aˉi)
其中 A ˉ i \bar A_i Aˉi A i A_i Ai的补集

那么如何切图可以让子图内的点权重和高,子图间的点权重和低呢?

一个自然的想法就是最小化 c u t ( A 1 , A 2 , . . . A k ) cut(A_1,A_2,...A_k) cut(A1,A2,...Ak), 但是可以发现,这种极小化的切图存在问题,如下图:
在这里插入图片描述

为了避免最小切图导致的切图效果不佳,我们需要对每个子图的规模做出限定,一般来说,有两种切图方式,第一种是 R a t i o C u t RatioCut RatioCut,第二种是 N c u t Ncut Ncut

4.1 R a t i o C u t RatioCut RatioCut切图

对于每个切图,不仅要考虑最小化 c u t ( A 1 , A 2 , . . . , A k ) cut(A_1,A_2,...,A_k) cut(A1,A2,...,Ak),还要考虑最大化每个子图样本的个数,即最小化 R a t i o C u t RatioCut RatioCut函数:
R a t i o C u t ( A 1 , A 2 , . . . , A k ) = 1 2 ∑ i = 1 k W ( A i , A ˉ i ) ∣ A i ∣ RatioCut(A_1,A_2,...,A_k)=\frac {1} {2}\sum_{i=1}^k\frac {W(A_i, \bar A_i)}{|A_i|} RatioCut(A1,A2,...,Ak)=21i=1kAiW(Ai,Aˉi)

我们引入指示向量 h j ∈ { h 1 , h 2 , . . . , h k } h_j\in \{h_1,h_2,...,h_k\} hj{h1,h2,...,hk},对于任意一个向量 h j = ( h 1 , j , h 2 , j , . . . , h n , j ) T h_j=(h_{1,j},h_{2,j},...,h_{n,j})^T hj=(h1,j,h2,j,...,hn,j)T,它是一个 n n n维向量( n n n为样本数),我们定义 h i j h_{ij} hij为:
h i j = { 0 v i ∉ A j 1 ∣ A j ∣ v i ∈ A j h_{ij}= \begin{cases} 0 & v_i \notin A_j \\ \frac {1} {|A_j|} & v_i \in A_j \end{cases} hij={0Aj1vi/AjviAj
对于 h i T L h i h_i^TLh_i hiTLhi有:
h i T L h i = 1 2 ∑ m = 1 ∑ n = 1 w m n ( h m , i − h n , i ) 2 = 1 2 ( ∑ m ∈ A i , n ∉ A i w m n ( 1 ∣ A i ∣ − 0 ) 2 + ∑ m ∉ A i , n ∈ A i w m n ( 0 − 1 ∣ A i ∣ ) 2 ) = 1 2 ( ∑ m ∈ A i , n ∉ A i w m n 1 ∣ A i ∣ + ∑ m ∉ A i , n ∈ A i w m n 1 ∣ A i ∣ ) = 1 2 ( c u t ( A i , A ˉ i ) 1 ∣ A i ∣ + c u t ( A i , A ˉ i ) 1 ∣ A i ∣ ) = c u t ( A i , A ˉ i ) ∣ A i ∣ h_i^TLh_i=\frac {1} {2}\sum_{m=1}\sum_{n=1}w_{mn}(h_{m,i}-h_{n,i})^2 \\ =\frac {1}{2}(\sum_{m \in A_i, n \notin A_i}w_{mn}(\frac {1}{\sqrt {|A_i|}}-0)^2+\sum_{m \notin A_i, n \in A_i}w_{mn}(0-\frac {1} {\sqrt {|A_i|}})^2)\\=\frac {1}{2}(\sum_{m \in A_i,n \notin A_i}w_{mn}\frac {1}{|A_i|}+\sum_{m \notin A_i,n \in A_i}w_{mn}\frac {1}{|A_i|})\\=\frac {1}{2}(cut(A_i,\bar A_i)\frac{1}{|A_i|}+cut(A_i,\bar A_i)\frac{1}{|A_i|})=\frac {cut(A_i,\bar A_i)} {|A_i|} hiTLhi=21m=1n=1wmn(hm,ihn,i)2=21(mAi,n/Aiwmn(Ai 10)2+m/Ai,nAiwmn(0Ai 1)2)=21(mAi,n/AiwmnAi1+m/Ai,nAiwmnAi1)=21(cut(Ai,Aˉi)Ai1+cut(Ai,Aˉi)Ai1)=Aicut(Ai,Aˉi)

由上式可知, R a t i o C u t RatioCut RatioCut函数表达式可改写为:
R a t i o C u t ( A 1 , A 2 , . . . , A k ) = ∑ i = 1 k h i T L h i = ∑ i = 1 k ( H T L H ) i i = t r ( H T L H ) RatioCut(A_1,A_2,...,A_k)=\sum_{i=1}^kh_i^TLh_i=\sum_{i=1}^k(H^TLH)_{ii}=tr(H^TLH) RatioCut(A1,A2,...,Ak)=i=1khiTLhi=i=1k(HTLH)ii=tr(HTLH)
其中 t r ( H T L H ) tr(H^TLH) tr(HTLH)为矩阵的迹,即我们的 R a t i o C u t RatioCut RatioCut切图,实际上是最小化迹 t r ( H T L H ) tr(H^TLH) tr(HTLH)。注意到 H T H = I H^TH=I HTH=I,则我们的优化目标为:
a r g min ⁡ H t r ( H T L H ) s . t . H T H = I arg\min_{H}tr(H^TLH)\\s.t. \quad H^TH=I argHmintr(HTLH)s.t.HTH=I

注意观察 t r ( H T L H ) tr(H^TLH) tr(HTLH)的每一个优化子目标 h i T L h i h_i^TLh_i hiTLhi,其中 h i h_i hi是单位正交基, L L L是对称矩阵,此时 h i T L h i h_i^TLh_i hiTLhi是矩阵 L L L的一个特征值。对于 h i T L h i h_i^TLh_i hiTLhi,我们的目标是找到矩阵 L L L的最小特征值,而对于 t r ( H T L H ) = ∑ i = 1 k h i T L h i tr(H^TLH)=\sum_{i=1}^kh_i^TLh_i tr(HTLH)=i=1khiTLhi,我们的目标就是找到矩阵 L L L k k k个最小特征值。

4.2 N c u t Ncut Ncut切图

N c u t Ncut Ncut切图与 R a t i o Ratio Ratio切图类似,只是将 R a t i o C u t RatioCut RatioCut的分母 ∣ A i ∣ |A_i| Ai换成 v o l ( A i ) vol(A_i) vol(Ai)。由于子图样本的个数多不一定权重就大,我们切图时基于权重也更符合我们的目标,因此一般来说 N c u t Ncut Ncut优于 R a t i o C u t RatioCut RatioCut,定义如下:
N c u t ( A 1 , A 2 , . . . , A k ) = 1 2 ∑ i = 1 k W ( A i , A ˉ i ) v o l ( A i ) Ncut(A_1,A_2,...,A_k)=\frac {1} {2}\sum_{i=1}^k\frac {W(A_i,\bar A_i)}{vol(A_i)} Ncut(A1,A2,...,Ak)=21i=1kvol(Ai)W(Ai,Aˉi)

对应的, N c u t Ncut Ncut切图对指示向量 h h h做了改进,定义如下:
h i j = { 0 v i ∉ A j 1 v o l ( A j ) v i ∈ A j h_{ij}= \begin{cases} 0 & v_i \notin A_j \\ \frac {1} {\sqrt {vol(A_j)}} & v_i \in A_j \end{cases} hij={0vol(Aj) 1vi/AjviAj

我们的优化目标依然是:(推导与 R a t i o C u t RatioCut RatioCut完全一致)
N c u t ( A 1 , A 2 , . . . , A k ) = ∑ i = 1 k h i T L h i = ∑ i = 1 k ( H T L H ) i i = t r ( H T L H ) Ncut(A_1,A_2,...,A_k)=\sum_{i=1}^kh_i^TLh_i=\sum_{i=1}^k(H^TLH)_{ii}=tr(H^TLH) Ncut(A1,A2,...,Ak)=i=1khiTLhi=i=1k(HTLH)ii=tr(HTLH)
但是此时我们的 H T H ≠ I H^TH \not=I HTH=I,而是 H T D H = I H^TDH=I HTDH=I。推导如下:
h i T D h i = ∑ j = 1 n h j i 2 d j = ∑ j ∈ A i 1 v o l ( A i ) d j = 1 v o l ( A i ) ∑ j ∈ A i d j = 1 v o l ( A i ) v o l ( A i ) = 1 h_i^TDh_i=\sum_{j=1}^nh_{ji}^2d_j=\sum_{j \in A_i}\frac {1} {vol(A_i)}d_j=\frac {1} {vol(A_i)}\sum_{j \in A_i}d_j=\frac {1} {vol(A_i)}vol(A_i)=1 hiTDhi=j=1nhji2dj=jAivol(Ai)1dj=vol(Ai)1jAidj=vol(Ai)1vol(Ai)=1
也就是说,我们的优化目标最终为:
a r g min ⁡ H t r ( H T L H ) s . t . H T D H = I arg\min_{H}tr(H^TLH) \\ s.t. \quad H^TDH=I argHmintr(HTLH)s.t.HTDH=I
此时我们的 H H H中的指示向量 h h h不是单位正交基,所以我们令 H = D − 1 2 F H=D^{-\frac {1} {2}}F H=D21F,则 H T L H = F T D − 1 2 L D − 1 2 F , H T D H = F T F = I H^TLH=F^TD^{-\frac {1}{2}}LD^{-\frac {1}{2}}F,H^TDH=F^TF=I HTLH=FTD21LD21F,HTDH=FTF=I,也就是优化目标变成了:
a r g min ⁡ F t r ( F T D − 1 2 L D − 1 2 F ) s . t . F T F = I arg\min_{F}tr(F^TD^{-\frac {1}{2}}LD^{-\frac {1}{2}}F) \\ s.t. \quad F^TF=I argFmintr(FTD21LD21F)s.t.FTF=I
可以发现这个式子和 R a t i o C u t RatioCut RatioCut基本一致,只是中间的 L L L变成了 D − 1 2 L D − 1 2 D^{-\frac {1}{2}}LD^{-\frac {1}{2}} D21LD21。这样,我们可以按照 R a t i o C u t RatioCut RatioCut的思想,求出 D − 1 2 L D − 1 2 D^{-\frac {1}{2}}LD^{-\frac {1}{2}} D21LD21 k k k个最小特征值

一般来说, D − 1 2 L D − 1 2 D^{-\frac {1}{2}}LD^{-\frac {1}{2}} D21LD21相当于对拉普拉斯矩阵 L L L做了一次标准化,即 L i j d i ⋅ d j \frac {L_{ij}}{\sqrt {d_i \cdot d_j}} didj Lij

5. 谱聚类算法流程

输 入 : 样 本 集 D = ( x 1 , x 2 , . . . , x n ) , 邻 接 矩 阵 的 生 成 方 式 , 降 维 后 的 维 度 k 1 , 聚 类 方 法 , 聚 类 后 的 维 度 k 2 输入:样本集D=(x_1,x_2,...,x_n),邻接矩阵的生成方式, 降维后的维度k_1, 聚类方法,聚类后的维度k_2 D=(x1,x2,...,xn),k1,k2

输 出 : 簇 划 分 C ( c 1 , c 2 , . . . c k 2 ) 输出: 簇划分C(c_1,c_2,...c_{k_2}) C(c1,c2,...ck2)

  1. 根据邻接矩阵生成方式构建邻接矩阵 W W W,构建度矩阵 D D D
  2. 计算出拉普拉斯矩阵 L L L
  3. 构建标准化后的拉普拉斯矩阵 D − 1 2 L D − 1 2 D^{-\frac {1}{2}}LD^{-\frac {1}{2}} D21LD21
  4. 计算 D − 1 2 L D − 1 2 D^{-\frac {1}{2}}LD^{-\frac {1}{2}} D21LD21最小的 k 1 k_1 k1个特征值所各自对应的特征向量 f f f
  5. 将各自对应的特征向量 f f f组成的矩阵按行标准化,最终组成 n × k 1 n \times k_1 n×k1维矩阵 F F F
  6. F F F中的每一行作为一个 k 1 k_1 k1维样本,共 n n n个样本,用输入的聚类方法进行聚类,聚类维数为 k 2 k_2 k2
  7. 得到簇划分 C ( c 1 , c 2 , . . . c k 2 ) C(c_1,c_2,...c_{k_2}) C(c1,c2,...ck2)

6. 实例演示

import numpy as np 
import matplotlib.pyplot as plt from sklearn import cluster, datasets
from sklearn.preprocessing import StandardScalernp.random.seed(0)# 构建数据
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=0.5, noise=0.05)
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=0.05)
blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)data_sets = [(noisy_circles,{"n_clusters": 2}),(noisy_moons,{"n_clusters": 2}), (blobs, {"n_clusters": 3})
]
colors = ["#377eb8", "#ff7f00", "#4daf4a"]
affinity_list = ['rbf', 'nearest_neighbors']plt.figure(figsize=(17, 10))for i_dataset, (dataset, algo_params) in enumerate(data_sets):# 模型参数params = algo_params# 数据X, y = datasetX = StandardScaler().fit_transform(X)for i_affinity, affinity_strategy in enumerate(affinity_list):# 创建SpectralClusterspectral = cluster.SpectralClustering(n_clusters=params['n_clusters'],eigen_solver='arpack', affinity=affinity_strategy)# 训练spectral.fit(X)# 预测y_pred = spectral.labels_.astype(int)y_pred_colors = []for i in y_pred:y_pred_colors.append(colors[i])plt.subplot(3, 4, 4*i_dataset+i_affinity+1)plt.title(affinity_strategy)plt.scatter(X[:, 0], X[:, 1], color=y_pred_colors)plt.show()

在这里插入图片描述

7. 谱聚类算法小结

优点:

  1. 谱聚类只需要数据之间的邻接矩阵,因此对于处理稀疏数据的聚类很有效。这点传统聚类算法比如K-Means很难做到
  2. 由于使用了降维,因此在处理高维数据聚类时的复杂度比传统聚类算法好

缺点:

  1. 如果最终聚类的维度非常高,则由于降维的幅度不够,谱聚类的运行速度和最后的聚类效果均不好
  2. 聚类效果依赖于邻接矩阵,不同的邻接矩阵得到的最终聚类效果可能很不同

http://chatgpt.dhexx.cn/article/vvjloI3Y.shtml

相关文章

非常全面的谱聚类算法原理总结

谱聚类算法是目前最流行的聚类算法之一,其性能及适用场景优于传统的聚类算法如k-均值算法,本文对谱聚类算法进行了详细总结,内容主要参考论文《A Tutorial on Spectral Clustering》,下载链接:https://github.com/zhan…

C语言遍历文件目录:readdir,opendir

环境&#xff1a;Linux系统 头文件&#xff1a; #include<sys/types.h> #include<dirent.h> 一、opendir 原型 DIR* opendir (const char * path ); 参数与功能 path为目录路径&#xff0c;打开一个目录&#xff0c;在失败的时候返回一个空的指针。 返回值…

嵌入式学习之Linux系统编程---9 目录IO之readdir函数

1、readdir函数的函数原型 #include <dirent.h> struct dirent *readdir(DIR *dirp);对于readdir函数来说&#xff0c;它只有目录流指针这一个参数&#xff0c;这个目录流指针就是使用opendir这个函数的返回值。 该函数在man手册的第三页&#xff0c;该函数如果执行成功…

readdir函数解析

函数原型: struct dirent *readdir(DIR *dirp); 首先纠正一个很多人都错误理解的事实,readdir不是系统调用,它是glibc的封装函数,而且readdir系统调用是存在的,原型如下: int readdir(unsigend int fd, struct old_linux_dirent *dirp, unsigned int count); glibc的readdi…

C/C++的readdir和readdir_r函数(遍历目录)

1.首先要打开目录文件 DIR *opendir( const char *name); DIR *fdopendir( int fd); 2.读取目录文件信息的函数 注意&#xff1a;这是个库函数 struct dirent *readdir( DIR *dirp); int readdir_r( DIR *dirp, struct dirent *entry, struct dirent **res…

Linux下 C 遍历目录(opendir,readdir函数)

opendir()函数: 头文件&#xff1a; #include <sys/types.h> #include <dirent.h> 函数原型&#xff1a; Dir* opendir(const char* pathname); 函数功能&#xff1a; 获取pathname目录下的所有文件和目录的列表&#xff0c;如果pathname是个文件或失败则返…

linux——读取文件(read)

ssize_t read(int fd, void *buf, size_t count); 将fd中的内容读取到buf中。 代码&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #inc…

linux的readdir和readdir_r函数

1.首先要打开目录文件 DIR *opendir( const char *name); DIR *fdopendir( int fd); 2.读取目录文件信息的函数 注意&#xff1a;这是个库函数 struct dirent *readdir( DIR *dirp); int readdir_r( DIR *dirp, struct dirent *entry, struct dirent **res…

readdir函数

readdir会不断读取目中的文件及目录&#xff0c;但不会读子目录中的文件。 #include <sys/types.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <dirent.h> int main() {DIR *dirp opendir("/home/python/Des…

readdir不保证读取的文件顺序

readdir用于读取某个文件夹中的全部文件或文件夹&#xff0c;相当于ls。 但是readdir并不保证读取后的文件顺序&#xff0c;在不同的操作系统上可能有不同的顺序。 在某些场景下需要注意&#xff0c;比如读取配置文件时&#xff0c;可能会根据配置文件进行一些初始化&#xf…

Ubuntu 18.04安装远程桌面

Ubuntu 18.04安装远程桌面 陈拓 2021/08/05-2020/08/08 1. Putty登录 IP地址 192.168.0.103 登录账户 ccdc xxxxxxxx 2. Ubuntu 18.04安装桌面 如果安装的系统已经带桌面跳过这一步。 2.1 查看linux系统版本 lsb_release -a 2.2 安装桌面 sudo apt-get install ubun…

ubuntu远程桌面连接windows

ubuntu远程桌面连接windows 1&#xff1a;使用ubuntu自带软件remmina 2&#xff1a;打开该软件后&#xff0c;点击长方形 3&#xff1a; 服务器&#xff1a;windows电脑内网ip 用户名&#xff1a;电脑用户名 密码&#xff1a;电脑用户名的登陆密码 点击右下角&#xff1a;保存…

Ubuntu 远程桌面的方式

提示&#xff1a;仅仅是按照记忆所写的笔记&#xff0c;如果你看到这篇笔记&#xff0c;按照操作出了问题&#xff0c;评论就好了&#xff0c;我会完善一下。笔记内容以外的问题不要评论&#xff0c;我不管。 vino & dconf-editor 该方式适用于ubuntu desktop 18.04 及以后…

Ubuntu18.04远程桌面连接

一、安装 xrdp、tightvncserver sudo apt-get install tightvncserver xrdp二、安装xubuntu-desktop sudo apt-get install xubuntu-desktop三、修改配置文件 echo xfce4-session >~/.xsession sudo vi /etc/xrdp/startwm.sh在下图位置加入"xfce4-session" 在…

多ubuntu主机远程桌面连接方案

一、需求背景 公司有一批ubuntu的主机&#xff0c;需要研发远程上去进行代码调试&#xff0c;普通的远程桌面方式不易于管理&#xff0c;并且无法进行连接控制。 二、方案制定 基于web的远程方案有Guacamole、NoVNC两种方案&#xff0c;但都不利于后期工具与公司整体的SSO进行对…

Ubuntu Server 18.04安装远程桌面并连接

文章目录 一、安装桌面环境Xfce二、安装 Xrdp三、设置root密码四、连接Xrdp服务器五、设置终端 尝试了很多种方法&#xff0c;折腾了一晚上终于搞出来了呜呜…顺便记录一下,以免下次忘记! 一、安装桌面环境Xfce Ubuntu 服务器通常使用命令行进行管理&#xff0c;并且默认没有安…

Windows10远程桌面Ubuntu16.04

自己的笔记本配置太低&#xff0c;有很多图形界面的软件&#xff0c;需要在服务器上运行&#xff0c;通常只用SSH方式访问的命令行方式是无法实现的。 虽然配置XShell XManager可以实现打开图形程序&#xff0c;但速度之慢&#xff0c;即使内网也无法忍受。 今天来推荐一个更…

Ubuntu 安装远程桌面

转自&#xff1a;https://blog.csdn.net/heyangyi_19940703/article/details/77994416 1.安装xrdp软件: 运行Terminal,执行以下命令&#xff1a; sudo apt-get -y install xfce4 xrdp vnc4server 2.安装完成&#xff0c;查看下相关软件包 执行命令&#xff1a; dpkg -L xrdp…

Ubuntu 系统下如何远程访问 Windows 桌面 ?

你一定听说过 Windows 应用程序远程桌面连接。该应用程序系统自带不用安装&#xff0c;并允许您远程访问另一台 PC 或服务器。它使用远程桌面协议建立远程桌面连接会话。 一些 Linux 发行版可能会提供 RDP 客户端来连接到 Windows 系统。但是&#xff0c;对于某些 linux 发行版…

ubuntu20.04远程桌面这样装

我的记录本 安装了新系统之后&#xff0c;直接就进行了远程桌面的测试1.系统设置2.安装xrdp3.安装dconf-editor并设置4.切换windows系统打开远程桌面 安装了新系统之后&#xff0c;直接就进行了远程桌面的测试 更新源都没有动&#xff0c;直接进行远程桌面的测试。 参考文献&a…