【数据结构】图论入门

引入

数据的逻辑结构:

  1. 集合:数据元素间除“同属于一个集合”外,无其他关系
  2. 线性结构:一个对多个,例如:线性表、栈、队列
  3. 树形结构:一个对多个,例如:树
  4. 图形结构:多个对多个,例如:图

图的基本概念及术语

图:G = ( V, E )

V:顶点(数据元素)的有穷非空集合

E:边的有穷集合

图的类型定义

无向图:每条边都是无方向的

在这里插入图片描述

有向图:每条弧都是有方向的

在这里插入图片描述

完全图:任意两个点都有一条边相连

  1. 无向完全图:n个结点就有n * (n - 1) / 2 条边
  2. 有向完全图:n个结点就有n * (n - 1) 条边

稀疏图:有很少的边或者弧的图(通常 m 远小于nlog(n))

稠密图:有较多的边或者弧的图(通常 m 大于nlog(n))

连通图:在无(有)向图G = (V,{E})中,若对任意两个顶点v、u,都存在v到u的路径,则称G是连通图(强连通图)

图的基本术语

  1. 网:边或者弧带权(有值)的图

  2. 邻接:有边 / 弧相连的两个顶点之间的关系

    • 存在(Vi,Vj),则称 Vi 和 Vj 互为邻接点(无向图)
    • 存在 <Vi,Vj>,则称 Vi 邻接到Vj,Vj 邻接于 Vi(有向图)
  3. 关联(依附):边 / 弧与顶点之间的关系

    存在(Vi,Vj)/ <Vi,Vj>,则称该边/弧关联与Vi和Vj

  4. 顶点的度:与该顶点相关联的边的数目,记为TD(V)

    在有向图当中,顶点的度等于该顶点的入度与出度之和

    顶点V的入度是以V为终点的有向边的条数

    以上图为例:

    ​ 对于上面的有向图来说,每个结点的度都为2

    ​ 对于上面的无向图来说,每个结点的度都为3,但是不同结点的入度、出度不一样(V3入度为1,出度为2)

  5. 路径:连接的边构成的顶点序列

  6. 路径长度:路径上边/弧的数目/权值之和

  7. 回路(环):第一个顶点和最后一个顶点相同的路径

  8. 简单路径:除路径起点和终点可以相同之外,其余顶点均不相同的路径

  9. 简单回路(简单环):除路径起点和终点相同之外,其余顶点均不相同的路径

  10. 子图:设有两个图G = (V,{E}),G1 = (V1,{E1}),若V1属于V并且E1属于E,则称G1是G的子图

  11. 连通分量(强连通分量):无(有)向图的极大连通子图称为G的连通分量(强连通分量)

    • 极大连通子图:该子图是G连通子图,将G的任何不在该子图的顶点加入,此图不再连续
    • 极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边,此子图不再连续

图的存储结构

数组(邻接矩阵)表示法

概述

建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间的关系)

  1. 设图A = (V,E)有n个顶点,则顶点表Vext[n]表示为

    i01n-1
    Vext[i]V1V2Vn
  2. 图的邻接矩阵是一个二维数组A.arcs[n][n],定义为:

    当存在<i,j>或者( i,j )属于图中的边或者弧,我们就将A.arcs[i][j]赋值为1,否则为0

举例

无向图

在这里插入图片描述

具体形况根据顶点的值去建立顶点表

邻接矩阵:

V1V2V3V4V5
V101010
V210101
V301011
V410100
V501100

特点:

  1. 无向图的邻接矩阵是对称的
  2. 顶点i的度 = 第i行(列)中1的个数
  3. 完全图的邻接矩阵中,对角元素为0,其余为1

代码演示见下面遍历部分

有向图

在这里插入图片描述

邻接矩阵:

v1v2v3v4
v10110
v20000
v30001
v41000

特点:

  1. 有向图的邻接矩阵可能是不对称的

  2. 顶点的出度 = 第i行元素之和

    顶点的入度 = 第i列元素之和

    顶点的度 = 出度 + 入度

网的邻接矩阵就是将1用权值替换

代码演示见下面遍历部分

优缺点

优点:

  1. 直观,简单,好理解
  2. 方便检查任意一对顶点间是否存在边
  3. 方便找任意顶点的所有邻接点
  4. 方便计算出任意顶点的度

缺点:

  1. 不利于增加和删除顶点
  2. 浪费空间:存稀疏图,有大量无效元素
  3. 浪费时间:统计稀疏图中共有多少条边

邻接表

顶点:按编号顺序将顶点数据存储在一维数组中

关联同一顶点的边(以顶点为尾的弧):用线性链表存储

举例

仍以上图为例

无向图:

在这里插入图片描述

特点:

  1. 邻接表不唯一
  2. 若无向图中有n个顶点e条边,则其邻接表需n个头结点和2e个表结点,适宜存储稀疏图
  3. 无向图中顶点vi的度为第i个单链表中的结点数

代码演示见下面遍历部分

有向图:

在这里插入图片描述

特点:

  1. 顶点vi的出度为第i个单链表中的结点个数
  2. 顶点vi的入度为整个单链表中邻接点域值是i-1的结点个数

代码演示见下面遍历部分

邻接矩阵与邻接表的关系:

1.联系:邻接表中每个链表对应于邻接矩阵中的每一行,链表中结点个数等于一行中非零元素的个数

2.区别:

a.对于任意确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一致),但邻接表不唯一(连接次序与顶点编号无关)
b.邻接矩阵的空间复杂度为O(n^2),而连接表的空间复杂度为O(n+e)

图的遍历

定义:从已给的连通图中某一顶点出发,沿着一些边访问图中所有的顶点,且每个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算

实质:找每个顶点的邻接点的过程

问题:由图的特点,图中可能出现回路,且图的任一顶点都可能与其他结点相遇,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点,怎么避免重复访问?

解决思路:设置辅助数组a[n],用来标记每个被访问过的顶点,初始状态都为0,当顶点i被访问,改a[i]为1,防止被多次访问

深度优先搜索(DFS)

方法:

  1. 在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1
  2. 再由w1出发访问与w1邻接,但还未被访问过的顶点w2
  3. 然后再从w2出发进行类似的访问…
  4. 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止
  5. 接着退回一步退到前一次刚访问过的顶点,看是否还有其他没有被访问的邻接顶点
  6. 如果有则访问此顶点,之后再从此顶点出发,进行与之前类似的访问
  7. 如果没有就再退回一步进行搜索,重复上述过程,直到连通图中所有顶点都被访问过为止

注意:

  1. 稠密图适于在邻接矩阵上进行深度遍历
  2. 稀疏图适于在连接表上进行深度遍历

对于邻接矩阵的代码演示:

public class GraphAdjacencyMatrix {
    private int V; // 顶点的数量
    private int[][] matrix; // 邻接矩阵
    private boolean[] visited;
    // 构造函数
    public GraphAdjacencyMatrix(int v) {
        V = v;
        matrix = new int[v][v];
        visited = new boolean[v];
        for (int i = 0; i < v; i++) {
            visited[i] = false;
        }
    }

    // 添加边
    public void addEdge(int v, int w, int weight) {
        matrix[v][w] = weight; // 因为是无向图,所以需要添加两个方向的边
        matrix[w][v] = weight;
    }

    //深度优先遍历
    private void DFS(int v) {
        visited[v] = true;
        System.out.print(v + " ");

        for (int i = 0; i < V; i++) {
            if (matrix[v][i] == 1 && !visited[i]) {
                DFS(i);
            }
        }
    }

    // 遍历所有顶点(如果顶点未访问,则进行DFS)
    public void DFSTraversal() {
        for (int i = 0; i < V; i++) {
            if (!visited[i]) {
                DFS(i); // 从顶点i开始DFS
            }
        }
    }

    // 打印图
    public void printGraph() {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                if (matrix[i][j] == 0) {
                    System.out.print("0 ");
                } else {
                    System.out.print(matrix[i][j] + " ");
                }
            }
            System.out.println();
        }
    }
}
public class linjiejuzhen {
    public static void main(String[] args) {
        GraphAdjacencyMatrix graph = new GraphAdjacencyMatrix(4);

        graph.addEdge(0, 1, 10); // 添加边 0-1 权重为 10
        graph.addEdge(0, 2, 6);
        graph.addEdge(1, 2, 4);
        graph.addEdge(2, 3, 1);

        System.out.println("Adjacency Matrix:");
        graph.printGraph();
        System.out.println("Depth First Traversal starting from vertex 0: ");
        graph.DFSTraversal(); //0 1 2 3
    }
}
Adjacency Matrix:
0 10 6 0 
10 0 4 0 
6 4 0 1 
0 0 1 0 
Depth First Traversal starting from vertex 0: 
0 1 2 3 

对于邻接表代码演示:

import java.util.Iterator;
import java.util.LinkedList;

public class DirectedGraphAdjacencyList {
    private int V; // 顶点的数量
    private LinkedList<Integer> adj[];
    private boolean visited[]; // 邻接表

    // 构造函数
    public DirectedGraphAdjacencyList(int v) {
        V = v;
        adj = new LinkedList[v];
        visited = new boolean[v];
        for (int i = 0; i < v; i++) {
            adj[i] = new LinkedList<>();
            visited[i] = false;
        }
    }

    // 添加边
    public void addEdge(int v, int w) {
        adj[v].add(w); // 添加从顶点v到顶点w的有向边
    }

    // 打印图
    public void printGraph() {
        for (int i = 0; i < V; i++) {
            System.out.print("Vertex " + i + ":");
            Iterator<Integer> it = adj[i].iterator();
            while (it.hasNext()) {
                System.out.print(" -> " + it.next());
            }
            System.out.println();
        }
    }

    private void DFS(int v) {
        visited[v] = true;
        System.out.print(v + " ");

        Iterator<Integer> i = adj[v].listIterator();
        while (i.hasNext()) {
            int n = i.next();
            if (!visited[n]) {
                DFS(n); // 递归访问未访问的邻接顶点
            }
        }
    }

    // 遍历所有顶点执行DFS
    public void DFSTraversal() {
        for (int i = 0; i < V; i++) {
            if (!visited[i]) {
                DFS(i); // 从顶点i开始DFS
            }
        }
    }
}
public class DirectedGraphAdjacency {
    public static void main(String[] args) {
        DirectedGraphAdjacencyList graph = new DirectedGraphAdjacencyList(6);

        // 添加有向边
        graph.addEdge(5, 0);
        graph.addEdge(5, 3);
        graph.addEdge(4, 0);
        graph.addEdge(4, 1);
        graph.addEdge(2, 3);
        graph.addEdge(3, 1);
        graph.addEdge(1, 3);

        System.out.println("Adjacency List Representation of Directed Graph:");
        graph.printGraph();
        System.out.println("Depth First Traversal starting from vertex 0: ");
        graph.DFSTraversal(); //0 1 3 2 4 5
    }
}
Adjacency List Representation of Directed Graph:
Vertex 0:
Vertex 1: -> 3
Vertex 2: -> 3
Vertex 3: -> 1
Vertex 4: -> 0 -> 1
Vertex 5: -> 0 -> 3
Depth First Traversal starting from vertex 0: 
0 1 3 2 4 5 

广度优先搜索(BFS)

方法:

从图的某一结点出发,首先依次访问该结点的所有邻接结点 Vi1、Vi2……Vin,再按这些顶点被访问的先后次序依次访问与他们相邻接的所有未被访问的顶点。重复此过程,直至所有顶点均被访问为止

对于邻接矩阵的代码演示

import java.util.LinkedList;
import java.util.Queue;

public class DirectedGraphAdjacencyMatrix {
    private int V; // 顶点的数量
    private int[][] matrix; // 邻接矩阵
    private boolean[] visited;

    // 构造函数
    public DirectedGraphAdjacencyMatrix(int v) {
        V = v;
        matrix = new int[v][v];
        visited = new boolean[v];
        // 初始化矩阵,所有元素都设置为0,表示没有边
        for (int i = 0; i < v; i++) {
            for (int j = 0; j < v; j++) {
                matrix[i][j] = 0;
            }
            visited[i] = false;
        }
    }

    // 添加边
    public void addEdge(int v, int w, int weight) {
        matrix[v][w] = weight; // 只在矩阵的对应位置添加边的权重
    }

    // 打印图
    public void printGraph() {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                if (matrix[i][j] == 0) {
                    System.out.print(" 0 ");
                } else {
                    System.out.print(" " + matrix[i][j] + " ");
                }
            }
            System.out.println();
        }
    }
    //广度优先搜索
    public void BFS(int start) {
        Queue<Integer> queue = new LinkedList<>();
        visited[start] = true; // 标记起始顶点为已访问
        queue.add(start); // 将起始顶点添加到队列中

        while (!queue.isEmpty()) {
            int v = queue.poll(); // 从队列中取出一个顶点
            System.out.print(v + " ");

            for (int i = 0; i < V; i++) {
                if (matrix[v][i] != 0 && !visited[i]) {
                    visited[i] = true; // 标记邻接顶点为已访问
                    queue.add(i); // 将邻接顶点添加到队列中
                }
            }
        }
    }
}
public class linjiejuzhenYou {
    public static void main(String[] args) {
        DirectedGraphAdjacencyMatrix graph = new DirectedGraphAdjacencyMatrix(4);

        graph.addEdge(0, 1, 10); // 添加有向边 0->1 权重为 10
        graph.addEdge(0, 2, 6);
        graph.addEdge(1, 2, 4);
        graph.addEdge(1, 3, 1);
        graph.addEdge(2, 3, 7);

        System.out.println("Directed Adjacency Matrix:");
        graph.printGraph();
        System.out.println("Breadth First Traversal starting from vertex 0: ");
        graph.BFS(0); //0 1 2 3
    }
}
Directed Adjacency Matrix:
 0  10  6  0 
 0  0  4  1 
 0  0  0  7 
 0  0  0  0 
Breadth First Traversal starting from vertex 0: 
0 1 2 3 

对于邻接表的代码演示

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class UndirectedGraphAdjacencyList {
    private int V; // 顶点的数量
    private LinkedList<Integer> adj[]; // 邻接表
    private boolean[] visited;

    // 构造函数
    public UndirectedGraphAdjacencyList(int v) {
        V = v;
        visited = new boolean[V];
        adj = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            adj[i] = new LinkedList<>();
            visited[i] = false;
        }
    }

    // 添加边
    public void addEdge(int v, int w) {
        adj[v].add(w); // 添加从v到w的边
        adj[w].add(v); // 因为是无向图,所以需要添加从w到v的边
    }

    // 打印图
    public void printGraph() {
        for (int i = 0; i < V; i++) {
            System.out.print("Vertex " + i + ":");
            Iterator<Integer> it = adj[i].iterator();
            while (it.hasNext()) {
                System.out.print(" -> " + it.next());
            }
            System.out.println();
        }
    }

    public void BFS(int start) {
        Queue<Integer> queue = new LinkedList<>();
        visited[start] = true; // 标记起始顶点为已访问
        queue.add(start); // 将起始顶点添加到队列中

        while (!queue.isEmpty()) {
            int v = queue.poll(); // 从队列中取出一个顶点
            System.out.print(v + " ");

            Iterator<Integer> i = adj[v].listIterator();
            while (i.hasNext()) {
                int n = i.next();
                if (!visited[n]) {
                    visited[n] = true; // 标记邻接顶点为已访问
                    queue.add(n); // 将邻接顶点添加到队列中
                }
            }
        }
    }
}
public class UndirectedGraphAdjacency {
    public static void main(String[] args) {
        UndirectedGraphAdjacencyList graph = new UndirectedGraphAdjacencyList(4);

        graph.addEdge(0, 1); // 添加边 0-1
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 3);

        System.out.println("Adjacency List Representation of Undirected Graph:");
        graph.printGraph();
        System.out.println("Breadth First Traversal starting from vertex 0: ");
        graph.BFS(0); //0 1 2 3
    }
}
Adjacency List Representation of Undirected Graph:
Vertex 0: -> 1 -> 2
Vertex 1: -> 0 -> 2
Vertex 2: -> 0 -> 1 -> 3
Vertex 3: -> 2
Breadth First Traversal starting from vertex 0: 
0 1 2 3 

二者搜索的算法分析

时间复杂度:

邻接矩阵:
对于邻接矩阵表示的图,时间复杂度主要受两个因素影响:

  1. 矩阵大小:邻接矩阵的大小为 𝑉×𝑉,其中 V 是顶点的数量。

  2. 遍历矩阵:你需要遍历整个邻接矩阵来检查每个顶点的所有邻接点。

因此,对于邻接矩阵表示的图,时间复杂度为 𝑂(𝑉^2),这是因为你需要检查 V 个顶点,每个顶点可能与其他 V 个顶点相连。

邻接表:
对于邻接表表示的图,时间复杂度分析如下:

  1. 顶点数量:图有 V 个顶点。

  2. 边的数量:图有 E 条边。

  3. 访问邻接表:你访问每个顶点的邻接表,每个邻接表包含与该顶点直接相连的顶点。

  4. 队列操作:使用队列(栈)来存储待访问的顶点,每次从队列(栈)中取出一个顶点,并将其所有未访问的邻接顶点加入队列(栈)。

因此,对于邻接表表示的图,时间复杂度为 O(V+E)。这是因为你访问了所有 V 个顶点,并且每个顶点的邻接表(即所有边)也被访问了一次。

空间复杂度:空间复杂度相同,都是O(n)

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

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

相关文章

C++基础编程100题-005 OpenJudge-1.3-03 计算(a+b)/c的值

更多资源请关注纽扣编程微信公众号 http://noi.openjudge.cn/ch0103/03/ 描述 给定3个整数a、b、c&#xff0c;计算表达式(ab)/c的值&#xff0c;/是整除运算。 输入 输入仅一行&#xff0c;包括三个整数a、b、c, 数与数之间以一个空格分开。(&#xff0d;10,000 < a,…

创新指南 | 5个行之有效的初创企业增长策略

本文探讨了五种初创企业实现快速增长的有效策略&#xff1a;利用网络效应通过激励和资本化用户增长&#xff1b;通过持续提供高质量内容建立信任和权威的内容营销&#xff1b;利用简单有效的推荐计划扩展用户群&#xff1b;采用敏捷开发方法快速适应市场变化和客户反馈&#xf…

Flink中因java的泛型擦除导致的报错及解决

【报错】 Exception in thread "main" org.apache.flink.api.common.functions.InvalidTypesException: The return type of function Custom Source could not be determined automatically, due to type erasure. You can give type information hints by using th…

【Stable Diffusion】(基础篇二)—— Stable Diffusion图形界面介绍和基本使用流程

本系列笔记主要参考B站nenly同学的视频教程&#xff0c;传送门&#xff1a;B站第一套系统的AI绘画课&#xff01;零基础学会Stable Diffusion&#xff0c;这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 在上一篇博客中&#xff0c;我们成功…

【红黑树变色+旋转】

文章目录 一. 红黑树规则二. 情况一叔叔存在且为红情况二.变色旋旋 一. 红黑树规则 对于红黑树&#xff0c;进行变色旋转处理&#xff0c;终究都是为了维持颜色以下几条规则&#xff0c;只有颜色和规则维持住了&#xff0c;红黑树就维持住了最长路径的长度不超过最短路径的两倍…

MySQL之查询性能优化(十)

查询性能优化 MySQL查询优化器的局限性 松散索引扫描 由于历史原因&#xff0c;MySQL并不支持松散索引扫描&#xff0c;也就无法按照不连续的方式扫描一个索引。通常&#xff0c;MySQL的索引扫描需要先定义一个起点和终点&#xff0c;即使需要的数据只是这段索引中很少数的几…

WSDM2022推荐系统相关论文整理(一)

2022年第15届国际网络搜索与数据挖掘会议WSDM在2022年2月21日到25日于线上举行&#xff0c;共收到了786份有效投稿&#xff0c;最终录取篇数为159篇&#xff0c;录取率为20.23%。作为主流的搜索与数据挖掘会议&#xff0c;论文的话题主要侧重于搜索、推荐以及数据挖掘领域&…

【机器学习基础】Python编程06:五个实用练习题的解析与总结

Python是一种广泛使用的高级编程语言,它在机器学习领域中的重要性主要体现在以下几个方面: 简洁易学:Python语法简洁清晰,易于学习,使得初学者能够快速上手机器学习项目。 丰富的库支持:Python拥有大量的机器学习库,如scikit-learn、TensorFlow、Keras和PyTorch等,这些…

【BOM02】本地存储

一&#xff1a;什么是本地存储 数据存储在用户浏览器中&#xff0c;用户设置、读取方便&#xff0c;同时页面刷新时不会丢失数据。存储在浏览器中数据约5M&#xff0c;分为sessionStorage和localStorage两种存储方式 二&#xff1a;localStorage存储 作用 将数据永久存储在…

SSM整合总结

一.核心问题 (一)两个容器 web容器 web相关组件&#xff08;controller,springmvc核心组件&#xff09; root容器 业务和持久层相关组件&#xff08;service,aop,tx,dataSource,mybatis,mapper等&#xff09; 父容器&#xff1a;root容器&#xff0c;盛放service、mapper、…

【人工智能】流行且重要的智能算法整理

✍&#x1f3fb;记录学习过程中的输出&#xff0c;坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;指点&#x1f64f; 小记&#xff1a; 今天在看之前写的文档时&#xff0c;发现有人工智能十大算法的内容&#xf…

Java概述 , Java环境安装 , 第一个Hello World

环境变量,HelloWorld 1.会常用的dos命令 2.会安装java所需要的环境(jdk) 3.会配置java的环境变量 4.知道java开发三步骤 5.会java的入门程序(HelloWorld) 6.会三种注释方式 7.知道Java入门程序所需要注意的地方 8.知道println和print的区别第一章 Java概述 1.1 JavaSE体系介绍…

Django 里的表格内容做修改

当Django里表格内容需要做修改&#xff0c;可以这么操作。 先看效果图 修改后的表格 1. 先得在 asset_list.html 里修改。你们的html有可能跟我不一样 <table border"1px"><thead><tr><th>ID</th><th>标题</th><th…

软件测试--Linux快速入门

文章目录 软件测试-需要掌握的Linux指令Linux命令操作技巧Linx命令的基本组成常用命令 软件测试-需要掌握的Linux指令 Linux命令操作技巧 使用Tab键自动补全上下键进行翻找之前输入的命令命令执行后无法停止使用CtrC,结束屏幕输出 Linx命令的基本组成 命令 [-选项] [参数] …

1.Linux入门

文章目录 一、介绍1.1 操作系统1.2 Linux1.3 虚拟机1.4 安装 CentOS7 二、远程连接 Linux2.1 FinalShell2.2 远程连接Linux 三、扩展3.1 WSL3.2 虚拟机快照 一、介绍 1.1 操作系统 我们平常所用的电脑是个人桌面操作系统&#xff0c;也就是Windows或者是macOS 目前我们要学的…

(2024,ViT,小波变换,图像标记器,稀疏张量)基于小波的 ViT 图像标记器

Wavelet-Based Image Tokenizer for Vision Transformers 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0 摘要 1 引言 3 基于小波的图像压缩简介 4 图像标记器 4.1 像素空间标记嵌…

短视频直播教学课程小程序的作用是什么

只要短视频/直播做的好&#xff0c;营收通常都不在话下&#xff0c;近些年&#xff0c;线上自媒体行业热度非常高&#xff0c;每条细分赛道都有着博主/账号&#xff0c;其各种优势条件下也吸引着其他普通人冲入。 然无论老玩家还是新玩家&#xff0c;面对平台不断变化的规则和…

Docker搭建ELKF日志分析系统

Docker搭建ELKF日志分析系统 文章目录 Docker搭建ELKF日志分析系统资源列表基础环境一、系统环境准备1.1、创建所需的映射目录1.2、修改系统参数1.3、单击创建elk-kgc网络桥接 二、基于Dockerfile构建Elasticsearch镜像2.1、创建Elasticsearch工作目录2.2、上传资源到指定工作路…

鸿蒙开发的南向开发和北向开发

鸿蒙开发主要分为设备开发和应用开发两个方向&#xff0c;也叫南向开发和北向开发&#xff1a; 鸿蒙设备开发(南向开发&#xff09;&#xff0c;要侧重于硬件层面的开发&#xff0c;涉及硬件接口控制、设备驱动开发、鸿蒙系统内核开发等&#xff0c;目的是使硬件设备能够兼容并…

端午假期来临,来使用闪侠惠递便宜寄快递吧!

相信很多人和我一样&#xff0c;每当需要寄快递时&#xff0c;总是感到十分头疼。不同的快递公司有不同的价格、时效和服务质量等等&#xff0c;选择起来真的很不容易。但是现在有了闪侠惠递来帮大家寄快递吧&#xff0c;这个问题就可以迎刃而解了&#xff01;小编奉劝大家快来…