图的基本概念、图的存储、图的遍历(深度优先搜索、广度优先搜索、迪杰斯特拉算法)

一、图的应用场景:

  • ⽹络爬⾍;
  • 地图应⽤:⾼德地图,百度地图(最近距离推荐,最短时⻓推荐);
  • 社交⽹络分析:好友推荐,垃圾⽤户分析,社交关系分析(好友亲密度);
  • 推荐、精准营销;
  • 舆情控制,信息传播;
  • 防欺诈(⽹络诈骗和电信诈骗);
  • 计算⽣物学:模拟分⼦运动;

 

二、图的分类:

  •  (1)有向图:    全部边为有向边所构成的图称为有向图

应用:例如抖音用户关注博主(单向:用户关注博主,博主不关注用户)

  •     (2)无向图:    全部边为无向的边所构成的图称为无向图

  •  (3)权重图:    每条边上带有两个顶点之间的权重数字

权重数字通常由深度学习和机器学习计算出来。

应用:(1)QQ好友之间的请密度

           (2)地图软件的上所用的图基本上都是权重图,权重数字可以用来计算两地之间的最短路径等信息。

又分为有向权重图和无向权重图,下图所示为有向权重图。

 

三、图的基本概念:

  • 顶点集合(vex-set:如上图 S(vex) = {'A', 'B', 'C', 'D', 'E', 'F'}

  • 边集合(arc-set:如上图 S(arc) = {<'A', 'B'>, <'A', 'C'>, <'A', 'D'>, <'B', 'F'>, <'B', 'C'>, <'C', 'E'>, <'D', 'E'>, <'E', 'F'>}

  • 度(degree:⽆向图中从⼀个点延伸出去的边数就是该点的度;有向图中包含出度和⼊度;

  • 出度(out-degree:有多少条边指向某点就是该点的出度;

  • ⼊度(in-degree:有多少条边从另一个顶点有线连接到该点就是该点的入度

例如C的入度是1,出度是2

 

四、图的存储:

图存储的关键是点集合边集合。

  • (1)用邻接矩阵存储:

上面这个图的邻接矩阵如下图所示:    默认值为0,有关系的标为1

出度:看行求和,例如c的出度 = 3

入度:看列求和,例如c 的入度= 3

这里这个图是无向的,所以出度和入度是一样的

优点:很容易算出边邻接关系;以及顶点的度(不管是出度还是⼊度);

缺点:边集合存储空间复杂度⽐较⼤,图中存在⼤量的0,空间利⽤率不⾼(尤其在点多边少的情况 下);

对于⽆向图,邻接矩阵是对称的,可以只存下半部分,如下图所示。

 

利用无向图的数学关系可以只存无向图的下半部分,达到提高空间利用率的目的,但是实际运用过程中不可能用邻接矩阵来存储图,因为效率太低了。

  • (2)用连接表存储:

顶点集合依然存储在⼀维数组当中,边集合存储在连接表当中,能够很好的控制空间复杂度。

  • 有向图:

  • 无向图:

  • 权重无向图:

  • 优点:很容易算出邻接关系;以及节点的出度;

  • 缺点:很难算出⼊度,需要遍历整张表;可以建⽴⼀张逆连接表(相当于记录⼊度的表);

 

五、图的遍历:

  • 从图中某⼀个顶点出发,访问图中其余顶点,使每个顶点被访问⼀次且只被访问⼀次;

  • 可以从图中任意⼀个顶点出发进⾏遍历;

  • 需要解决的问题:

  • 确定⼀条搜索路径;

  • 确保每个顶点被访问到;

  • 确保每个顶点只能被访问⼀次;

  • 设置辅助数组visited,数组元素的初始值均为false,⼀旦遍历过就置为true

 

1)深度优先搜索:有点像二叉树的遍历,一头扎到尾,然后再回溯

 

应⽤:

  • 检测连通分量的个数;

  • 两个点是否在⼀个连通分量中;

  • 检测是否构成环;从⼀个点出发能否回到出发点;

 

(2)广度优先搜索:按层遍历,由近到远

  • 关键数据结构:队列;

  • 应⽤: 游戏中找寻路径问题;

 

(3)迪杰斯特拉算法(dijkstra):

  • 该算法主要解决最短路径问题,采⽤是贪⼼思想

  • 对象:权重图;

  • 该算法核⼼思想是:每次从路径最短的点出发遍历相邻边,检测修改路径值(确保相邻点也是最短),从未被确认路径最短的顶点集合中选择最短路径的点,将该点加⼊确认路径最短的顶点集,并将该点作为下次遍历相邻边的出发点

  • 核⼼步骤:更新,扫描,修改;

例如:

 

用贪心算法逐步去推算确认队列未确认队列

最终得到整个图的最短遍历顺序为ACEDBF

所以A到F的最短路径为 A B F 12+5 =17

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一些关于用 C 语言设计基于 DOS 菜单的应用程序的建议。首先,您需要使用 C 语言编写代码来实现所需的功能,包括创建无向、打印邻接矩阵或邻接表、深度优先遍历和广度优先遍历。接下来,您需要使用 DOS 命令行界面来创建交互式菜单,其中每个选项都对应着一个功能。您可以使用 switch 语句来实现菜单选项的选择,以及调用相应的函数来执行所需的操作。以下是一个简单的示例代码,供您参考: ``` #include <stdio.h> #include <stdlib.h> /* 定义无向结构体 */ typedef struct { int** adj_matrix; // 邻接矩阵 int num_vertices; // 顶点数 } Graph; /* 创建无向邻接矩阵 */ Graph* create_adj_matrix(int num_vertices) { Graph* graph = (Graph*) malloc(sizeof(Graph)); graph->num_vertices = num_vertices; graph->adj_matrix = (int**) malloc(num_vertices * sizeof(int*)); for (int i = 0; i < num_vertices; i++) { graph->adj_matrix[i] = (int*) malloc(num_vertices * sizeof(int)); for (int j = 0; j < num_vertices; j++) { graph->adj_matrix[i][j] = 0; } } return graph; } /* 打印邻接矩阵 */ void print_adj_matrix(Graph* graph) { printf("Adjacency Matrix:\n"); for (int i = 0; i < graph->num_vertices; i++) { for (int j = 0; j < graph->num_vertices; j++) { printf("%d ", graph->adj_matrix[i][j]); } printf("\n"); } } /* 创建无向邻接表 */ Graph* create_adj_list(int num_vertices) { Graph* graph = (Graph*) malloc(sizeof(Graph)); graph->num_vertices = num_vertices; graph->adj_matrix = (int**) malloc(num_vertices * sizeof(int*)); for (int i = 0; i < num_vertices; i++) { graph->adj_matrix[i] = NULL; } return graph; } /* 打印邻接表 */ void print_adj_list(Graph* graph) { printf("Adjacency List:\n"); for (int i = 0; i < graph->num_vertices; i++) { printf("%d: ", i); for (int j = 0; j < graph->num_vertices; j++) { if (graph->adj_matrix[i][j] == 1) { printf("%d ", j); } } printf("\n"); } } /* 深度优先遍历 */ void dfs(Graph* graph, int vertex, int* visited) { visited[vertex] = 1; printf("%d ", vertex); for (int i = 0; i < graph->num_vertices; i++) { if (graph->adj_matrix[vertex][i] == 1 && visited[i] == 0) { dfs(graph, i, visited); } } } /* 广度优先遍历 */ void bfs(Graph* graph, int vertex, int* visited) { int queue[graph->num_vertices]; int front = 0; int rear = -1; visited[vertex] = 1; queue[++rear] = vertex; while (front <= rear) { int v = queue[front++]; printf("%d ", v); for (int i = 0; i < graph->num_vertices; i++) { if (graph->adj_matrix[v][i] == 1 && visited[i] == 0) { visited[i] = 1; queue[++rear] = i; } } } } /* 主函数 */ int main() { int choice; int num_vertices; Graph* graph; int* visited; /* 显示菜单选项 */ do { printf("\n"); printf("1. Create adjacency matrix and print\n"); printf("2. Create adjacency list and print\n"); printf("3. Depth first search\n"); printf("4. Breadth first search\n"); printf("5. Exit\n"); printf("\nEnter your choice: "); scanf("%d", &choice); switch (choice) { case 1: /* 创建邻接矩阵 */ printf("Enter number of vertices: "); scanf("%d", &num_vertices); graph = create_adj_matrix(num_vertices); visited = (int*) malloc(num_vertices * sizeof(int)); for (int i = 0; i < num_vertices; i++) { visited[i] = 0; } /* 打印邻接矩阵 */ print_adj_matrix(graph); break; case 2: /* 创建邻接表 */ printf("Enter number of vertices: "); scanf("%d", &num_vertices); graph = create_adj_list(num_vertices); visited = (int*) malloc(num_vertices * sizeof(int)); for (int i = 0; i < num_vertices; i++) { visited[i] = 0; } /* 打印邻接表 */ print_adj_list(graph); break; case 3: /* 深度优先遍历 */ printf("Enter starting vertex: "); scanf("%d", &num_vertices); dfs(graph, num_vertices, visited); break; case 4: /* 广度优先遍历 */ printf("Enter starting vertex: "); scanf("%d", &num_vertices); bfs(graph, num_vertices, visited); break; case 5: /* 退出程序 */ exit(0); default: printf("Invalid choice!\n"); } } while (choice != 5); return 0; } ``` 请注意,以上代码仅提供了一种可能的实现方式,您可以根据自己的需求进行修改和优化。同时,您还需要在 DOS 命令行环境中编译和运行该程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值