目录

1.概念

​​​2.程序表示

①临接矩阵

②邻接表

3.遍历

①DFS

②BFS​

4.连通

5.实例

①拯救007

​​②六度空间

6.最短路径问题

①单源无权图

②单源有权图

③多源  ​​​

④例题:哈利波特的考试

7.最小生成树

①Prim算法​​

②Kruskal算法​​

8.拓扑排序

①概念

②关键路径问题

9.旅游规划


1.概念

2.程序表示

①临接矩阵

具体代码:

②邻接表

具体代码:

3.遍历

①DFS

/* 邻接表存储的图 - DFS */void Visit( Vertex V )
{printf("正在访问顶点%d\n", V);
}/* Visited[]为全局变量,已经初始化为false */
void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) )
{   /* 以V为出发点对邻接表存储的图Graph进行DFS搜索 */PtrToAdjVNode W;Visit( V ); /* 访问第V个顶点 */Visited[V] = true; /* 标记V已访问 */for( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */if ( !Visited[W->AdjV] )    /* 若W->AdjV未被访问 */DFS( Graph, W->AdjV, Visit );    /* 则递归访问之 */
}

②BFS

/* 邻接矩阵存储的图 - BFS *//* IsEdge(Graph, V, W)检查<V, W>是否图Graph中的一条边,即W是否V的邻接点。  */
/* 此函数根据图的不同类型要做不同的实现,关键取决于对不存在的边的表示方法。*/
/* 例如对有权图, 如果不存在的边被初始化为INFINITY, 则函数实现如下:         */
bool IsEdge( MGraph Graph, Vertex V, Vertex W )
{return Graph->G[V][W]<INFINITY ? true : false;
}/* Visited[]为全局变量,已经初始化为false */
void BFS ( MGraph Graph, Vertex S, void (*Visit)(Vertex) )
{   /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */Queue Q;     Vertex V, W;Q = CreateQueue( MaxSize ); /* 创建空队列, MaxSize为外部定义的常数 *//* 访问顶点S:此处可根据具体访问需要改写 */Visit( S );Visited[S] = true; /* 标记S已访问 */AddQ(Q, S); /* S入队列 */while ( !IsEmpty(Q) ) {V = DeleteQ(Q);  /* 弹出V */for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W *//* 若W是V的邻接点并且未访问过 */if ( !Visited[W] && IsEdge(Graph, V, W) ) {/* 访问顶点W */Visit( W );Visited[W] = true; /* 标记W已访问 */

4.连通

5.实例

①拯救007

②六度空间

6.最短路径问题

①单源无权图

/* 邻接表存储 - 无权图的单源最短路算法 *//* dist[]和path[]全部初始化为-1 */
void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S )
{Queue Q;Vertex V;PtrToAdjVNode W;Q = CreateQueue( Graph->Nv ); /* 创建空队列, MaxSize为外部定义的常数 */dist[S] = 0; /* 初始化源点 */AddQ (Q, S);while( !IsEmpty(Q) ){V = DeleteQ(Q);for ( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */if ( dist[W->AdjV]==-1 ) { /* 若W->AdjV未被访问过 */dist[W->AdjV] = dist[V]+1; /* W->AdjV到S的距离更新 */path[W->AdjV] = V; /* 将V记录在S到W->AdjV的路径上 */AddQ(Q, W->AdjV);}} /* while结束*/
}

②单源有权图

/* 邻接矩阵存储 - 有权图的单源最短路算法 */Vertex FindMinDist( MGraph Graph, int dist[], int collected[] )
{ /* 返回未被收录顶点中dist最小者 */Vertex MinV, V;int MinDist = INFINITY;for (V=0; V<Graph->Nv; V++) {if ( collected[V]==false && dist[V]<MinDist) {/* 若V未被收录,且dist[V]更小 */MinDist = dist[V]; /* 更新最小距离 */MinV = V; /* 更新对应顶点 */}}if (MinDist < INFINITY) /* 若找到最小dist */return MinV; /* 返回对应的顶点下标 */else return ERROR;  /* 若这样的顶点不存在,返回错误标记 */
}bool Dijkstra( MGraph Graph, int dist[], int path[], Vertex S )
{int collected[MaxVertexNum];Vertex V, W;/* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */for ( V=0; V<Graph->Nv; V++ ) {dist[V] = Graph->G[S][V];if ( dist[V]<INFINITY )path[V] = S;elsepath[V] = -1;collected[V] = false;}/* 先将起点收入集合 */dist[S] = 0;collected[S] = true;while (1) {/* V = 未被收录顶点中dist最小者 */V = FindMinDist( Graph, dist, collected );if ( V==ERROR ) /* 若这样的V不存在 */break;      /* 算法结束 */collected[V] = true;  /* 收录V */for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W *//* 若W是V的邻接点并且未被收录 */if ( collected[W]==false && Graph->G[V][W]<INFINITY ) {if ( Graph->G[V][W]<0 ) /* 若有负边 */return false; /* 不能正确解决,返回错误标记 *//* 若收录V使得dist[W]变小 */if ( dist[V]+Graph->G[V][W] < dist[W] ) {dist[W] = dist[V]+Graph->G[V][W]; /* 更新dist[W] */path[W] = V; /* 更新S到W的路径 */}}} /* while结束*/return true; /* 算法执行完毕,返回正确标记 */
}

③多源  

/* 邻接矩阵存储 - 多源最短路算法 */bool Floyd( MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] )
{Vertex i, j, k;/* 初始化 */for ( i=0; i<Graph->Nv; i++ )for( j=0; j<Graph->Nv; j++ ) {D[i][j] = Graph->G[i][j];path[i][j] = -1;}for( k=0; k<Graph->Nv; k++ )for( i=0; i<Graph->Nv; i++ )for( j=0; j<Graph->Nv; j++ )if( D[i][k] + D[k][j] < D[i][j] ) {D[i][j] = D[i][k] + D[k][j];if ( i==j && D[i][j]<0 ) /* 若发现负值圈 */return false; /* 不能正确解决,返回错误标记 */path[i][j] = k;}return true; /* 算法执行完毕,返回正确标记 */
}

④例题:哈利波特的考试

7.最小生成树

①Prim算法

/* 邻接矩阵存储 - Prim最小生成树算法 */Vertex FindMinDist( MGraph Graph, WeightType dist[] )
{ /* 返回未被收录顶点中dist最小者 */Vertex MinV, V;WeightType MinDist = INFINITY;for (V=0; V<Graph->Nv; V++) {if ( dist[V]!=0 && dist[V]<MinDist) {/* 若V未被收录,且dist[V]更小 */MinDist = dist[V]; /* 更新最小距离 */MinV = V; /* 更新对应顶点 */}}if (MinDist < INFINITY) /* 若找到最小dist */return MinV; /* 返回对应的顶点下标 */else return ERROR;  /* 若这样的顶点不存在,返回-1作为标记 */
}int Prim( MGraph Graph, LGraph MST )
{ /* 将最小生成树保存为邻接表存储的图MST,返回最小权重和 */WeightType dist[MaxVertexNum], TotalWeight;Vertex parent[MaxVertexNum], V, W;int VCount;Edge E;/* 初始化。默认初始点下标是0 */for (V=0; V<Graph->Nv; V++) {/* 这里假设若V到W没有直接的边,则Graph->G[V][W]定义为INFINITY */dist[V] = Graph->G[0][V];parent[V] = 0; /* 暂且定义所有顶点的父结点都是初始点0 */ }TotalWeight = 0; /* 初始化权重和     */VCount = 0;      /* 初始化收录的顶点数 *//* 创建包含所有顶点但没有边的图。注意用邻接表版本 */MST = CreateGraph(Graph->Nv);E = (Edge)malloc( sizeof(struct ENode) ); /* 建立空的边结点 *//* 将初始点0收录进MST */dist[0] = 0;VCount ++;parent[0] = -1; /* 当前树根是0 */while (1) {V = FindMinDist( Graph, dist );/* V = 未被收录顶点中dist最小者 */if ( V==ERROR ) /* 若这样的V不存在 */break;   /* 算法结束 *//* 将V及相应的边<parent[V], V>收录进MST */E->V1 = parent[V];E->V2 = V;E->Weight = dist[V];InsertEdge( MST, E );TotalWeight += dist[V];dist[V] = 0;VCount++;for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W */if ( dist[W]!=0 && Graph->G[V][W]<INFINITY ) {/* 若W是V的邻接点并且未被收录 */if ( Graph->G[V][W] < dist[W] ) {/* 若收录V使得dist[W]变小 */dist[W] = Graph->G[V][W]; /* 更新dist[W] */parent[W] = V; /* 更新树 */}}} /* while结束*/if ( VCount < Graph->Nv ) /* MST中收的顶点不到|V|个 */TotalWeight = ERROR;return TotalWeight;   /* 算法执行完毕,返回最小权重和或错误标记 */
}

②Kruskal算法

/* 邻接表存储 - Kruskal最小生成树算法 *//*-------------------- 顶点并查集定义 --------------------*/
typedef Vertex ElementType; /* 默认元素可以用非负整数表示 */
typedef Vertex SetName;     /* 默认用根结点的下标作为集合名称 */
typedef ElementType SetType[MaxVertexNum]; /* 假设集合元素下标从0开始 */void InitializeVSet( SetType S, int N )
{ /* 初始化并查集 */ElementType X;for ( X=0; X<N; X++ ) S[X] = -1;
}void Union( SetType S, SetName Root1, SetName Root2 )
{ /* 这里默认Root1和Root2是不同集合的根结点 *//* 保证小集合并入大集合 */if ( S[Root2] < S[Root1] ) { /* 如果集合2比较大 */S[Root2] += S[Root1];     /* 集合1并入集合2  */S[Root1] = Root2;}else {                         /* 如果集合1比较大 */S[Root1] += S[Root2];     /* 集合2并入集合1  */S[Root2] = Root1;}
}SetName Find( SetType S, ElementType X )
{ /* 默认集合元素全部初始化为-1 */if ( S[X] < 0 ) /* 找到集合的根 */return X;elsereturn S[X] = Find( S, S[X] ); /* 路径压缩 */
}bool CheckCycle( SetType VSet, Vertex V1, Vertex V2 )
{ /* 检查连接V1和V2的边是否在现有的最小生成树子集中构成回路 */Vertex Root1, Root2;Root1 = Find( VSet, V1 ); /* 得到V1所属的连通集名称 */Root2 = Find( VSet, V2 ); /* 得到V2所属的连通集名称 */if( Root1==Root2 ) /* 若V1和V2已经连通,则该边不能要 */return false;else { /* 否则该边可以被收集,同时将V1和V2并入同一连通集 */Union( VSet, Root1, Root2 );return true;}
}
/*-------------------- 并查集定义结束 --------------------*//*-------------------- 边的最小堆定义 --------------------*/
void PercDown( Edge ESet, int p, int N )
{ /* 改编代码4.24的PercDown( MaxHeap H, int p )    *//* 将N个元素的边数组中以ESet[p]为根的子堆调整为关于Weight的最小堆 */int Parent, Child;struct ENode X;X = ESet[p]; /* 取出根结点存放的值 */for( Parent=p; (Parent*2+1)<N; Parent=Child ) {Child = Parent * 2 + 1;if( (Child!=N-1) && (ESet[Child].Weight>ESet[Child+1].Weight) )Child++;  /* Child指向左右子结点的较小者 */if( X.Weight <= ESet[Child].Weight ) break; /* 找到了合适位置 */else  /* 下滤X */ESet[Parent] = ESet[Child];}ESet[Parent] = X;
}void InitializeESet( LGraph Graph, Edge ESet )
{ /* 将图的边存入数组ESet,并且初始化为最小堆 */Vertex V;PtrToAdjVNode W;int ECount;/* 将图的边存入数组ESet */ECount = 0;for ( V=0; V<Graph->Nv; V++ )for ( W=Graph->G[V].FirstEdge; W; W=W->Next )if ( V < W->AdjV ) { /* 避免重复录入无向图的边,只收V1<V2的边 */ESet[ECount].V1 = V;ESet[ECount].V2 = W->AdjV;ESet[ECount++].Weight = W->Weight;}/* 初始化为最小堆 */for ( ECount=Graph->Ne/2; ECount>=0; ECount-- )PercDown( ESet, ECount, Graph->Ne );
}int GetEdge( Edge ESet, int CurrentSize )
{ /* 给定当前堆的大小CurrentSize,将当前最小边位置弹出并调整堆 *//* 将最小边与当前堆的最后一个位置的边交换 */Swap( &ESet[0], &ESet[CurrentSize-1]);/* 将剩下的边继续调整成最小堆 */PercDown( ESet, 0, CurrentSize-1 );return CurrentSize-1; /* 返回最小边所在位置 */
}
/*-------------------- 最小堆定义结束 --------------------*/int Kruskal( LGraph Graph, LGraph MST )
{ /* 将最小生成树保存为邻接表存储的图MST,返回最小权重和 */WeightType TotalWeight;int ECount, NextEdge;SetType VSet; /* 顶点数组 */Edge ESet;    /* 边数组 */InitializeVSet( VSet, Graph->Nv ); /* 初始化顶点并查集 */ESet = (Edge)malloc( sizeof(struct ENode)*Graph->Ne );InitializeESet( Graph, ESet ); /* 初始化边的最小堆 *//* 创建包含所有顶点但没有边的图。注意用邻接表版本 */MST = CreateGraph(Graph->Nv);TotalWeight = 0; /* 初始化权重和     */ECount = 0;      /* 初始化收录的边数 */NextEdge = Graph->Ne; /* 原始边集的规模 */while ( ECount < Graph->Nv-1 ) {  /* 当收集的边不足以构成树时 */NextEdge = GetEdge( ESet, NextEdge ); /* 从边集中得到最小边的位置 */if (NextEdge < 0) /* 边集已空 */break;/* 如果该边的加入不构成回路,即两端结点不属于同一连通集 */if ( CheckCycle( VSet, ESet[NextEdge].V1, ESet[NextEdge].V2 )==true ) {/* 将该边插入MST */InsertEdge( MST, ESet+NextEdge );TotalWeight += ESet[NextEdge].Weight; /* 累计权重 */ECount++; /* 生成树中边数加1 */}}if ( ECount < Graph->Nv-1 )TotalWeight = -1; /* 设置错误标记,表示生成树不存在 */return TotalWeight;
}

8.拓扑排序

①概念

②关键路径问题

/* 邻接表存储 - 拓扑排序算法 */bool TopSort( LGraph Graph, Vertex TopOrder[] )
{ /* 对Graph进行拓扑排序,  TopOrder[]顺序存储排序后的顶点下标 */int Indegree[MaxVertexNum], cnt;Vertex V;PtrToAdjVNode W;Queue Q = CreateQueue( Graph->Nv );/* 初始化Indegree[] */for (V=0; V<Graph->Nv; V++)Indegree[V] = 0;/* 遍历图,得到Indegree[] */for (V=0; V<Graph->Nv; V++)for (W=Graph->G[V].FirstEdge; W; W=W->Next)Indegree[W->AdjV]++; /* 对有向边<V, W->AdjV>累计终点的入度 *//* 将所有入度为0的顶点入列 */for (V=0; V<Graph->Nv; V++)if ( Indegree[V]==0 )AddQ(Q, V);/* 下面进入拓扑排序 */ cnt = 0; while( !IsEmpty(Q) ){V = DeleteQ(Q); /* 弹出一个入度为0的顶点 */TopOrder[cnt++] = V; /* 将之存为结果序列的下一个元素 *//* 对V的每个邻接点W->AdjV */for ( W=Graph->G[V].FirstEdge; W; W=W->Next )if ( --Indegree[W->AdjV] == 0 )/* 若删除V使得W->AdjV入度为0 */AddQ(Q, W->AdjV); /* 则该顶点入列 */ } /* while结束*/if ( cnt != Graph->Nv )return false; /* 说明图中有回路, 返回不成功标志 */ elsereturn true;
}

9.旅游规划

数据结构之图知识点总结相关推荐

  1. 数据结构-图-知识点总结

    2019独角兽企业重金招聘Python工程师标准>>> 一.基本术语 图(graph):图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图, ...

  2. 大一新生必看,自学必看,里昂详解数据结构之图

    数据结构之图 有幸掌握浅薄知识,不吝分享,保持独立思考,自主学习,共同进步.另求关注,点赞,评论,感谢!(tips:主页有数据结构全部知识点,以及知识点讲解,建立完善的数据结构知识体) 核心算法思想 ...

  3. 数据结构之图的创建(邻接表)

    数据结构之图的基本概念中了解了图的基本概念,接下来对图的代码实现进行详解. 邻接无向图 1. 邻接表无向图介绍 邻接表无向图是指通过邻接表表示的无向图. 上面的图G1包含了"A,B,C,D, ...

  4. 八十五、Python | Leetcode数据结构之图和动态规划算法系列

    @Author:Runsen @Date:2020/7/7 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  5. (九)数据结构之“图”

    数据结构之"图" 图是什么 图的常用操作 图的深度/广度优先遍历 什么是深度/广度优先遍历 深度优先遍历算法口诀 广度优先遍历算法口诀 LeetCode:65.有效数字 LeetC ...

  6. python深度优先_python数据结构之图深度优先和广度优先实例详解

    本文实例讲述了python数据结构之图深度优先和广度优先用法.分享给大家供大家参考.具体如下: 首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到 ...

  7. 数据结构之图的应用:有向无环图

    数据结构之图的应用:有向无环图 思维导图: 有向无环图:(DAG) 解题方法: 例: 思维导图: 有向无环图:(DAG) 解题方法: 例: PS: 当运算顺序不唯一时,最后的有向无环图也不唯一.

  8. Dubbo思维导图知识点整理

    Dubbo思维导图知识点整理 下载地址:https://download.csdn.net/download/liuhenghui5201/12846897

  9. 导数与微分的知识点思维导图_高中生物思维导图知识点总结

    今天小编给大家整理一份高中生物思维导图知识点总结 ,打印出来给孩子学习吧,需要的请点下面赞同,并评论:我要高中生物思维导图知识点总结, 点头像私信获取,希望给你的孩子有所帮助. 刚开始学生物的时候,第 ...

最新文章

  1. 重启服务器之home下文件全没,小白宝典——树莓派实用工具分享(大神绕路)
  2. java编程最新图书_清华大学出版社-图书详情-《Java程序设计》
  3. 【kruskal】【倍增】严格次小生成树(P4180)
  4. 双层玻璃窗的功效模型matlab,数学建模实例双层玻璃的功效
  5. STM8学习笔记---PWM互补波形输出
  6. 当Node.js遇见Docker
  7. 【转】SpringMVC整合websocket实现消息推送及触发
  8. cmake静态编译以及安装带有opencv的静态库并调用
  9. Html meta 标签定义页面元信息 详解
  10. 计算机管理用房设置要求,党政机关办公用房管理系统解决方案
  11. MT6573添加新硬件模块驱动方法
  12. 阿里云ACE-第一天笔记
  13. allure企业级定制报告
  14. 清除计算机策略,利用组策略清除历史记录
  15. 监控不同外挂盘的硬盘io、查看linux命令运行时间和记录、iostat命令查看硬盘io、查看硬盘io的几种方法、定位到硬盘io高的dm
  16. android 常用机型尺寸_安卓手机屏幕多大合适?6.4英寸是“黄金尺寸”吗?
  17. 如何使用Windows Live Writer远程发布到WordPress
  18. IDEA原先有项目怎么再导入maven项目
  19. Docker 制作带有中文字体的镜像
  20. 很好很强大的FXTZ

热门文章

  1. 2009年上海中医药大学博士拟录取名单暨公、自费公示
  2. APISpace 二维码识别OCR API
  3. java计算机毕业设计高校学生资助管理信息系统MyBatis+系统+LW文档+源码+调试部署
  4. 计算机网络——IP编址(一篇带你读懂)
  5. 【LeetCode】1631. Path With Minimum Effort 最小体力消耗路径(Medium)(JAVA)每日一题
  6. 润和HH-SCDAYU200开发套件技术指南
  7. Android 实战项目 -- 登录主页、找回密码
  8. 即时定位与地图构建(SLAM)的相关研究
  9. Moco框架基础操作
  10. django框架——sweetalert前端插件、序列化组件、批量数据操作、分页器、Forms组件(上)