《数据结构》学习系列——图(中)

系列文章目录

目录

  • 图的遍历
    • 深度优先遍历
      • 递归算法
      • 堆栈算法
    • 广度优先搜索
  • 拓扑排序
    • 定义定理
    • 算法思想
    • 伪代码
  • 关键路径
    • 基本概念
    • 关键活动有关量
    • 数学公式
    • 伪代码
    • 时间复杂性


图的遍历

  • 从给定连通图的某一顶点出发,沿着一些边访问遍图中所有的顶点,且使每个顶点仅被访问一次,称为图的遍历(Graph Traversal)
  • 存在的问题:图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到曾经访问过的顶点。
    • 避免重复访问:设置一个标志顶点是否被访问过的辅助数组 visited[],它的初始状态为 0。在图的遍历过程中,一旦某一个顶点 i i i 被访问,就立即让 visited[i] 置为 1,防止它被多次访问

深度优先遍历

  • 深度优先遍历又被称为深度优先搜索 DFS (Depth First Search),其类似于树的先根遍历
  • 基本思想:
    • DFS在访问图中某一起始顶点 v v v 后,由 v v v 出发,访问它的任一邻接顶点 w 1 w_1 w1;再从 w 1 w_1 w1 出发,访问与 w 1 w_1 w1 邻接但还没有访问过的顶点 w 2 w_2 w2;然后再从 w 2 w_2 w2 出发,进行类似的访问。如此往下去,直至到达所有的邻接顶点都被访问过的顶点 u u u 为止。接着,退回一步,退到前一次访问过的顶点,看看还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止
      在这里插入图片描述

递归算法

伪代码

// 图的深度优先遍历的递归算法
DepthFirstSearch(v, visited)
{
	visited[v] = 1;
	p = adjacent(Head[v]);
	while (p != NULL)
	{
		if (visited[VerAdj(p) != 1])
		{
			DepthFirstSearch(VerAdj(p), visited)
			p = link(p);	
		}
	}
}

// 算法主体
DFS_Main()
{
	// 为辅助数组申请空间
	visited = new int[graphsize];
	// 数组初始化
	for (int k = 0; k < graphsize; k++)
	{
		visited[k] = 0;
		// 从序号为0的顶点出发,深度优先遍历图
		DepthFirstSearch(0, visited)
		delete[] visited;
	}
}

非连通图需要多次调用深度优先遍历算法

for i = 0 to n-1
{
	for j = 0 to n-1
	{
		if visited[j] = 0
		{
			DepthFirstSearch(v[j], visited)
		}
 	}	
}

算法分析

  • 图中有 n n n 个顶点, e e e 条边
  • 如果用邻接表存储,沿顶点的adjacent可以找到某个顶点 v v v 的所有邻接顶点 w w w。由于总共有 2 e 2e 2e(无向图)或 e e e(有向图)个边结点,所以扫描边的时间为 O ( e ) O(e) O(e)。而且对所有顶点递归访问 1 次,所以遍历图的时间复杂性为 O ( n + e ) O(n + e) O(n+e)
  • 如果用邻接矩阵存储,则查找每一个顶点的所有的边,所需时间为 O ( n ) O(n) O(n),则遍历图中所有的顶点所需的时间为 O ( n 2 ) O(n^2) O(n2)

堆栈算法

  • 可以利用堆栈实现深度优先遍历的非递归算法
  • 堆栈中存放已访问结点的还没有被访问的邻接顶点。每次弹出栈顶元素时,如其未被访问则访问该顶点,检查当前顶点的边链表,将还没有被访问的邻接顶点入栈,循环进行

基本思想
首先将所有顶点的visited[]值置为 0,初始顶点压入堆栈

  • ① 检测堆栈是否为空。若堆栈为空,则迭代结束;否则,从栈顶弹出一个顶点 v v v
  • ② 如果 v v v 未被访问过,则访问 v v v,将visited[v]值更新为 1,然后根据 v v v 的邻接顶点表,将 v v v 的未被访问的邻接顶点压入栈,执行步骤 ①
// 非递归实现深度优先遍历算法
void DFS(Graph &graph, int v) {
    stack<int> S;         // 创建栈S
    vector<bool> visited(graph.size(), false); // 初始化访问标记数组

    S.push(v);            // 将起始顶点压入栈

    while (!S.empty()) {  // 当栈不为空时
        int v = S.top();  // 弹出栈顶元素
        S.pop();

        if (!visited[v]) {
            cout << v << " ";  // 访问顶点
            visited[v] = true; // 标记为已访问

            // 获取顶点v的所有邻接顶点,并压入栈中
            for (auto p = graph.adjacent(v); p != nullptr; p = p->link) {
                if (!visited[p->VerAdj]) {
                    S.push(p->VerAdj);
                }
            }
        }
    }
}

在这里插入图片描述

算法分析

  • 如果使用邻接表表示图,则循环的总时间代价为 d 0 + d 1 + ⋯ + d n − 1 = O ( e ) d_0 + d_1 + \dots + d_{n-1} = O(e) d0+d1++dn1=O(e),其中 d i d_i di 是顶点 i i i 的度(无向图)或出度(有向图)。总的时间复杂度为 O ( n + e ) O(n + e) O(n+e)
  • 如果使用邻接矩阵,则对于每一个被访问的顶点,循环要检测矩阵中的 n n n 个元素,总的时间代价为 O ( n 2 ) O(n^2) O(n2)

广度优先搜索

  • 为了实现逐层访问,算法中使用了一个队列,以记忆正在访问的这一层和上一层的顶点,以便于向下一层访问
  • 与深度优先搜索过程一样,为避免重复访问,需要一个辅助数组visited[],为被访问过的顶点加标记
// BFS1 [初始化]
CREATEQ(Q);         // 创建队列 Q
for (int i = 1; i <= n; i++) 
    visited[i] = 0; // 初始化所有顶点为未访问
PRINT(v);           // 打印起始顶点
visited[v] = 1;     // 标记起始顶点为已访问
Q.enqueue(v);       // 起始顶点入队列

// BFS2 [广度优先遍历]
while (!Q.isEmpty()) {       // 当队列不为空时
    v = Q.dequeue();         // 队头元素出队
    p = adjacent(Head[v]);   // 获取当前顶点的邻接链表

    while (p != NULL) {      // 遍历邻接链表
        if (visited[p->VerAdj] == 0) { // 如果邻接顶点未被访问
            Q.enqueue(p->VerAdj);      // 将邻接顶点入队
            PRINT(p->VerAdj);          // 打印邻接顶点
            visited[p->VerAdj] = 1;    // 标记邻接顶点为已访问
        }
        p = p->link;        // 继续访问下一个邻接顶点
    }
}

算法分析

  • 如果使用邻接表表示图,则循环的总时间代价为 d 0 + d 1 + ⋯ + d n − 1 = O ( e ) d_0 + d_1 + \dots + d_{n-1} = O(e) d0+d1++dn1=O(e),其中 d i d_i di 是顶点 i i i 的度。总的时间复杂度为 O ( n + e ) O(n + e) O(n+e)
  • 如果使用邻接矩阵,则对于每一个被访问的顶点,循环要检测矩阵中的 n n n 个元素,总的时间代价为 O ( n 2 ) O(n^2) O(n2)

拓扑排序

  • AOV 网:在有向图中,用顶点表示活动,用有向边表示活动之间的先后关系,称这样的有向图为AOV网 (Activity On Vertex Network)}
    • 计划、施工过程、生产流程、程序流程等都是“工程”。除了很小的工程外,一般都把工程分为若干个叫做“活动”的子工程。完成了所有这些活动,这个工程就可以完成了
    • 例如,计算机专业学生的学习就是一个工程,每一门课程的学习就是整个工程的一些活动。其中有些课程要求先修课程,有些则不要求。这样,在有些课程之间有先后关系,有些课程可以并行地学习

在这里插入图片描述

定义定理

  • 在 AOV 网络中,如果活动 V i V_i Vi 必须在活动 V j V_j Vj 之前进行,则存在有向边 ⟨ V i , V j ⟩ \langle V_i, V_j \rangle Vi,Vj
  • AOV 网络中不能出现有向回路,即有向环。在 AOV 网络中如果出现了有向环,则意味着某项活动应以自己作为先决条件。因此,对给定的 AOV 网络,必须先判断它是否存在有向环
  • 拓扑序列:AOV 网中所有顶点排成的线性序列,要求每个活动的所有前驱活动都排在该活动前面
  • 拓扑排序:构造 AOV 网的拓扑序列的过程被称为拓扑排序
  • 如果通过拓扑排序能将 AOV 网络的所有顶点都排入一个拓扑有序的序列中,则该 AOV 网络中必定不会出现有向环;相反,如果得不到满足要求的拓扑有序序列,则说明 AOV 网络中存在有向环,此 AOV 网络所代表的工程是不可行的
  • 设图 G = ( V , E ) G = (V, E) G=(V,E) 是非循环图, V ( G ) ≠ ∅ V(G) \neq \emptyset V(G)=,则 G G G 中一定存在入度为零的顶点。
  • G = ( V , E ) G = (V, E) G=(V,E) 是非循环图, V ( G ) = { 1 , 2 , … , n } V(G) = \{1, 2, \dots, n\} V(G)={1,2,,n} e = ∣ E ( G ) ∣ e = |E(G)| e=E(G)。则算法是正确的,且算法的时间复杂性为 O ( n + e ) O(n + e) O(n+e)

算法思想

  • 拓扑排序算法的基本步骤
    • 从网中选择一个入度为 0 的顶点并将其输出
    • 从网中删除该顶点及其所有出边
    • 执行步骤 ① 和 ②,直至所有顶点都已输出,或网中剩余顶点入度均不为 0(说明网中存在回路,无法继续拓扑排序)
      注意:对于任何无回路的 AOV 网,其顶点均可排成拓扑序列,但其拓扑序列未必唯一

在这里插入图片描述

伪代码

  • 假定 AOV 网用邻接表的形式存储。为实现拓扑排序算法,事先需做好两项准备工作:
  • 建立一个数组count[],count[i]的元素值为顶点 i i i 的入度;
  • 建立一个堆栈,栈中存放入度为 0 的顶点,每当一个顶点的入度为 0,就将其压入栈
// TOrder1 [初始化]
// 计算 count 数组(每个顶点的入度)
for (int i = 1; i <= n; i++) 
    count[i] = 0; // 初始化所有顶点的入度为 0

// 遍历邻接表,计算每个顶点的入度
for (int i = 1; i <= n; i++) {
    p = adjacent(Head[i]); // 获取顶点 i 的邻接表头指针
    while (p != NULL) {    // 遍历邻接表
        count[VerAdj(p)]++; // 更新邻接顶点的入度
        p = p->link;        // 移动到下一个邻接点
    }
}

// 拓扑排序
top = 0; // 栈顶指针初始化为 0

// 将入度为 0 的顶点压入栈
for (int i = 1; i <= n; i++) {
    if (count[i] == 0) {
        stack[top] = i; // 顶点 i 入栈
        top++;          // 栈顶指针加 1
    }
}

for (int i = 1; i <= n; i++) {
    // 如果循环体执行了 n 次但栈为空,则说明图中存在回路
    if (top == 0) {
        PRINT("There is a cycle in the network!");
        RETURN;
    } else {
        // 栈顶元素出栈
        j = stack[top - 1];
        top--; // 栈顶指针减 1
        PRINT(j); // 输出顶点 j(拓扑序中的一个顶点)

        // 遍历顶点 j 的邻接表,更新邻接顶点的入度
        p = adjacent(Head[j]);
        while (p != NULL) {
            k = VerAdj(p);    // 获取邻接顶点
            count[k]--;       // 邻接顶点的入度减 1
            if (count[k] == 0) { // 如果邻接顶点入度变为 0,则压入栈
                stack[top] = k;
                top++;
            }
            p = p->link; // 继续遍历下一个邻接点
        }
    }
}


关键路径

基本概念

  • 如果在有向无环的带权图中

    • 用有向边表示一个工程中的各项活动 (Activity)
    • 用边上的权值表示活动的持续时间 (Duration)
    • 用顶点表示事件 (Event)
  • 则这样的有向图叫做用边表示活动的网络,简称AOE (Activity On Edges) 网络

    • 源点:表示整个工程的开始(入度为零)
    • 汇点:表示整个工程的结束(出度为零)
  • 在 AOE 网络中,有些活动必须顺序进行,有些活动可以并行进行

  • 从源点到各个顶点,以至从源点到汇点的有向路径可能不止一条。这些路径的长度也可能不同。完成不同路径的活动所需的时间虽然不同,但只有各条路径上所有活动都完成了,整个工程才算完成

  • 完成整个工程所需的时间取决于从源点到汇点的最长路径长度,即在这条路径上所有活动的持续时间之和。这条路径长度最长的路径被称为关键路径 (Critical Path)

  • 关键路径:从源点到汇点具有最大长度的路径称为关键路径

  • 路径长度:指路径上的各边权值之和

  • 关键活动:关键路径上的活动

在这里插入图片描述

关键活动有关量

  • 事件 v j v_j vj 的最早发生时间ve(j):

    • 从源点 v 0 v_0 v0 v j v_j vj 的最长路径长度。
  • 事件 v j v_j vj 的最迟发生时间vl(j):

    • 保证汇点的最早发生时间不推迟(即不推迟整个工程完成时间)的前提下,事件 v j v_j vj 允许的最迟发生时间,等于ve(n-1)减去从 v j v_j vj v n − 1 v_{n-1} vn1 的最长路径长度
  • 活动 a i a_i ai 的最早开始时间e(i):

    • 设活动 a i a_i ai 在有向边 ⟨ v j , v k ⟩ \langle v_j, v_k \rangle vj,vk 上,e(i)是从源点 v 0 v_0 v0 v j v_j vj 的最长路径长度。因此e(i) = ve(j)
  • 活动 a i a_i ai 的最迟开始时间l(i):

    • l(i)是在不会引起时间延误的前提下,该活动允许的最迟开始时间。设活动 a i a_i ai 在有向边 ⟨ v j , v k ⟩ \langle v_j, v_k \rangle vj,vk 上,则 l ( i ) = vl(k) − weight ( ⟨ j , k ⟩ ) l(i) = \texttt{vl(k)} - \texttt{weight}(\langle j, k \rangle) l(i)=vl(k)weight(⟨j,k⟩)

数学公式

  • 求所有事件的最早发生时间}:
    递推公式: // 拓扑排序正序
    ve(k) = { 0 , k = 0 max ⁡ { ve(j) + weight ( ⟨ j , k ⟩ ) } , ⟨ v j , v k ⟩ ∈ E ( G ) ,    k = 1 , 2 , … , n − 1 \texttt{ve(k)} = \begin{cases} 0, & k = 0 \\ \max\{\texttt{ve(j)} + \texttt{weight}(\langle j, k \rangle)\}, & \langle v_j, v_k \rangle \in E(G), \; k = 1, 2, \dots, n-1 \end{cases} ve(k)={0,max{ve(j)+weight(⟨j,k⟩)},k=0vj,vkE(G),k=1,2,,n1

  • 求所有事件的最迟发生时间}:
    递推公式:拓扑排序逆序
    vl(j) = { ve(n-1) , j = n − 1 min ⁡ { vl(k) − weight ( ⟨ j , k ⟩ ) } , ⟨ v j , v k ⟩ ∈ E ( G ) ,    j = n − 2 , n − 3 , … , 0 \texttt{vl(j)} = \begin{cases} \texttt{ve(n-1)}, & j = n-1 \\ \min\{\texttt{vl(k)} - \texttt{weight}(\langle j, k \rangle)\}, & \langle v_j, v_k \rangle \in E(G), \; j = n-2, n-3, \dots, 0 \end{cases} vl(j)={ve(n-1),min{vl(k)weight(⟨j,k⟩)},j=n1vj,vkE(G),j=n2,n3,,0

伪代码

思路
求关键活动的基本步骤:

  • 对 AOE 网进行拓扑排序,若网中有回路,则终止算法;按拓扑次序求出各顶点事件的最早发生时间 ve
  • 按拓扑序列的逆序求出各顶点事件的最迟发生时间 vl
  • 根据ve和vl的值,求出各活动的最早开始时间 e(i)与最迟开始时间l(i),若e(i) = l(i),则 i i i 是关键活动

在这里插入图片描述

// CPath1 - 计算事件的最早发生时间
// 初始化事件的最早发生时间
for (int i = 1; i <= n; i++) 
    ve[i] = 0; // 最早发生时间初始化为 0

// 按拓扑序计算事件的最早发生时间
for (int i = 1; i <= n; i++) {
    p = adjacent(Head[i]); // 获取顶点 i 的邻接表
    while (p != NULL) {
        k = VerAdj(p); // 获取邻接顶点
        if (ve[i] + cost(p) > ve[k]) // 更新最早发生时间
            ve[k] = ve[i] + cost(p);
        p = p->link; // 继续访问下一个邻接点
    }
}


// CPath2 - 计算事件的最迟发生时间
// 初始化事件的最迟发生时间
for (int i = 1; i <= n; i++) 
    vl[i] = ve[n]; // 最迟发生时间初始化为最后事件的最早时间

// 按拓扑逆序计算事件的最迟发生时间
for (int i = n; i >= 1; i--) {
    p = adjacent(Head[i]); // 获取顶点 i 的邻接表
    while (p != NULL) {
        k = VerAdj(p); // 获取邻接顶点
        if (vl[k] - cost(p) < vl[i]) // 更新最迟发生时间
            vl[i] = vl[k] - cost(p);
        p = p->link; // 继续访问下一个邻接点
    }
}

// CPath3 - 关键活动的最早开始时间和最迟开始时间
// 遍历所有活动,计算关键活动
for (int i = 1; i <= n; i++) {
    p = adjacent(Head[i]); // 获取顶点 i 的邻接表
    while (p != NULL) {
        k = VerAdj(p); // 获取邻接顶点
        e = ve[i]; // 最早开始时间
        l = vl[k] - cost(p); // 最迟开始时间
        if (e == l) // 如果最早时间等于最迟时间,则为关键活动
            PRINT("<", i, ",", k, "> is Critical Activity!");
        p = p->link; // 继续访问下一个邻接点
    }
}

时间复杂性

  • 时间复杂性:对顶点进行拓扑排序的时间复杂性为 O ( n + e ) O(n + e) O(n+e),以拓扑次序求ve[i]和按拓扑逆序求vl[i]}时,所需时间均为 O ( e ) O(e) O(e)。求各个活动的e[k]和l[k]的时间复杂度为 O ( e ) O(e) O(e),整个算法的时间复杂性是 O ( n + e ) O(n + e) O(n+e)
  • 定理 6.3:任意的非空 AOE 网至少存在一条关键路径
  • 推论 6.1:假设边 ⟨ T i , T j ⟩ \langle T_i, T_j \rangle Ti,Tj 属于 AOE 网,则有
    vl[j] − ve[i] ≥ Weight ( ⟨ T i , T j ⟩ ) \texttt{vl[j]} - \texttt{ve[i]} \geq \texttt{Weight}(\langle T_i, T_j \rangle) vl[j]ve[i]Weight(⟨Ti,Tj⟩)
  • 且如果 ⟨ T i , T j ⟩ \langle T_i, T_j \rangle Ti,Tj 属于某一条关键路径,则有
    vl[j] − ve[i] = Weight ( ⟨ T i , T j ⟩ ) . \texttt{vl[j]} - \texttt{ve[i]} = \texttt{Weight}(\langle T_i, T_j \rangle). vl[j]ve[i]=Weight(⟨Ti,Tj⟩).

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32编程小工具FlyMcu和STLINK Utility 《通俗易懂》破解

FlyMcu FlyMcu 模拟仿真软件是一款用于 STM32 芯片 ISP 串口烧录程序的专用工具&#xff0c;免费&#xff0c;且较为非常容易下手&#xff0c;好用便捷。 注意&#xff1a;STM32 芯片的 ISP 下载&#xff0c;只能使用串口1&#xff08;USART1&#xff09;&#xff0c;对应的串口…

非递归遍历二叉树(数据结构)

我的博客主页 非递归遍历二叉树 前序遍历&#xff08;迭代&#xff09;中序遍历&#xff08;迭代&#xff09;后续遍历&#xff08;迭代&#xff09; 二叉树的遍历方式有&#xff1a;前序遍历、中序遍历、后续遍历&#xff0c;层序遍历&#xff0c;而树的大部分情况下都是通过递…

对于某些原型或UI软件的个人看法(2024/11)

由于我这几天&#xff0c;一边敲代码&#xff0c;一边进行页面布局设计与编码&#xff0c;发现可能就一个卡片&#xff0c;我都得调很久样式&#xff0c;觉得这样改很累也没效率&#xff0c;页面也不是很美观。所以我想到了ui设计&#xff0c;我可以先进行ui设计&#xff0c;然…

Rocky DEM tutorial4_SAG mill 半自磨机 -后处理

文章目录 3. 后处理3.1 磨损分析 - 3D3.2 磨损分析 - 2D3.3 导出磨损后的几何3.4颗粒轨迹3.5欧拉统计3.6 能谱分析介绍Enjoy!案例链接注:案例来自于Rocky官方教程3. 后处理 3.1 磨损分析 - 3D 点击Geometries --> Mill,点击Properties,选择 add new custom property …

目标检测指标-以及YOLOv1简介

一、物体检测评估指标 1.1 IOU IOU就是交并比&#xff0c;交集和并集之比&#xff0c;GT就是Ground-Truth真实值&#xff0c;红色的就是预测值。 我们希望预测值与真实值越接近越好&#xff0c;IOU越大越好。 1.2 MAP 如上图&#xff0c;右上角Actual是真实值&#xff0c;左边…

C++:用红黑树封装map与set-2

文章目录 前言一、红黑树封装map与set中const迭代器1. 框架的搭建2. set实现const迭代器3. map实现const迭代器 二、operator[ ]1. operator[ ]要达成的样子2. insert的改变 三. 解决insert里set中的问题四. 解决map中的operator[ ]总结用红黑树封装map与set代码 前言 前面我们…

jmeter5.6.3安装教程

一、官网下载 需要提前配置好jdk的环境变量 jmeter官网&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 选择点击二进制的zip文件 下载成功后&#xff0c;默认解压下一步&#xff0c;更改安装路径就行(我安装在D盘) 实用jmeter的bin目录作为系统变量 然后把这…

你最擅长使用哪个异步编程模式?

前言 异步编程模式指的是在进行异步编程时所采用的一种编程模式&#xff0c;主要包括TAP、EAP和APM三种模式。 TAP&#xff08;Task-based Asynchronous Pattern&#xff09;模式是.NET 4.0中引入的一种异步编程模式&#xff0c;它基于Task类实现&#xff0c;通过Task类的实例…

Linux高阶——1117—TCP客户端服务端

目录 1、sock.h socket常用函数 网络初始化函数 首次响应函数 测试IO处理函数 获取时间函数 总代码 2、sock.c SOCKET() ACCEPT()——服务端使用这个函数等待客户端连接 CONNECT()——客户端使用这个函数连接服务端 BIND()——一般只有服务端使用 LISTEN()——服务端…

1.5万字长文Java集合与数据结构面试题(注:该篇博客将会持续维护 最新维护时间:2024年11月25日)

&#x1f9f8;本篇博客重在讲解Java集合与数据结构面试题&#xff0c;将会实时更新&#xff0c;欢迎大家添加作者文末联系方式交流 &#x1f4dc;JAVA面试题专栏&#xff1a;JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 &#x1f4dc;作者首页&#xff1a; dream_rea…

[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式

T. 已测试目录 主机类型主机版本Docker镜像版本结果WSL2Ubuntu22.04Ubuntu20.04PASSWSL2Ubuntu22.04Ubuntu18.04PASS R. 软硬件要求&#xff1a; 编译硬件需求&#xff1a;做多系统测试&#xff0c;磁盘500GB起步(固态)&#xff08;机械会卡死&#xff09;&#xff0c;内存3…

40分钟学 Go 语言高并发:【实战】并发安全的配置管理器

【实战】并发安全的配置管理器 一、课程概述 学习要点重要程度掌握目标配置热更新★★★★★理解配置热更新原理&#xff0c;实现动态加载配置并发读写控制★★★★★掌握并发安全的读写控制机制观察者模式★★★★☆理解并实现配置变更通知机制版本管理★★★★☆实现配置版…

游戏陪玩系统开发功能需求分析

电竞游戏陪玩系统是一种专门为游戏玩家提供陪伴、指导和互动服务的平台。这类系统通常通过专业的陪玩师&#xff08;也称为陪练师&#xff09;为玩家提供一对一或多对一的游戏陪伴服务&#xff0c;帮助玩家提升游戏技能、享受游戏乐趣&#xff0c;甚至解决游戏中的各种问题。电…

Idea修改Commit Changes模式、idea使用git缺少部分Commit Changes

文章目录 一、模式一1、页面效果如下2、如何打开为这种样式&#xff1f; 二、模式二1、页面效果如下2、如何打开为这种样式&#xff1f; 三、总结 前言&#xff1a;Idea中代码提交到git库时的commit Change有两种模式&#xff0c;每种模式的界面及功能都不太一样。 Commit Cha…

飞书会话消息左右排列

飞书会话消息左右排列 1. 飞书登录后&#xff0c;点击头像&#xff0c;弹出菜单有个按钮设置 2. 3.

VUE3项目 关于金额:分转化为元 ;元转化为分;

1.在components 文件夹下新建moneyHandle.ts 文件 2.ts文件中写如下代码&#xff08;保留两位小数&#xff09; //分转化为元 - 正则解决精度 export const regFenToYuan (fen:any) >{var num fen;numfen*0.01;num;var reg num.indexOf(.) >-1 ? /(\d{1,3})(?(?:…

【linux学习指南】初识Linux进程信号与使用

文章目录 &#x1f4dd;信号快速认识&#x1f4f6;⽣活⻆度的信号&#x1f4f6; 技术应⽤⻆度的信号&#x1f309; 前台进程&#xff08;键盘&#xff09;&#x1f309;⼀个系统函数 &#x1f4f6;信号概念&#x1f4f6;查看信号 &#x1f320; 信号处理&#x1f309; 忽略此信…

蒙特卡洛方法(Monte Carlo,MC)

目录 1 序言 2 Monte Carlo法计算积分 3 最优化计算Monte Carlo法 1 序言 蒙特卡罗方法(Monte Carlo)是由冯诺依曼和乌拉姆等人发明的&#xff0c;“蒙特卡罗”这个名字是出自摩纳哥的蒙特卡罗赌场&#xff0c;这个方法是一类基于概率的方法的统称。是一种应用随机数来进行…

【ROS2】ROS2 构建系统 colcon 介绍、安装与使用

目录 一、ament 与 colcon二、colcon 模块化安装三、colcon 基本使用介绍3.1 常用命令构建工作空间清理构建结果构建特定的包指定构建系统并行构建扩展构建选项 3.2 其他命令列出所有可用的包忽略某些包查看colcon文档 一、ament 与 colcon ROS2采用了新的编译系统Ament&#…

Unity 2020、2021、2022、2023、6000下载安装

Unity 2020、2021、2022、2023、6000 下载安装 以Unity 6000.0.24fc1下载安装为例&#xff1a; 打开 https://unity.cn/ 优三缔 官方网站&#xff1b; 点击【产品列表】→点击【查看更多】→选择自己需要的版本→点【开始使用】 点击【从Unity Hub下载】 以Windows为例&am…