C语言《数据结构》(朱战立):图
C语言数据结构:图
一、图的基本概念
1、图的定义
G=(V,E)
- V{x|x∈某个数据元素集合}:表示顶点
- E{(x,y)|x,y∈V}:表示路径,若指定Path(x,y),说明x到y是一条单向通路,若不指定则是无向的。
2、图的基本术语
顶点和边:图中结点称为顶点,两个顶点相关联,这称两顶点间有条边
有向图和无向图:<x,y>,<y,x>表示边有方向,(x,y)表示边无方向
无向完全图:在n个顶点的无向图中,任意两个顶点间有且只有一条边(n(n-1)/2条边)
有向完全图:在n个顶点的有向图中,任意两个顶点之间有且只有方向相反的两条边(n(n-1))
邻接顶点:一条边的两个点称为邻接顶点
顶点的度:指与某一顶点相关联的边的条数,有几条边就有多少度
路径:从一个顶点到另外一个顶点的序列
权:边的附带信息
路径长度:不带权的图,路径的长度就行路径上边的条数。带权的图,路径的长度,是边上权的总和
子图:G1={V1,E2}和G2{V2,E2},若V2∈V1,E2属于E1,则G2是G1的子图
连通图:无向图中,任意两个顶点都能连通
强连通图,有向图中,任意两个顶点都能连通
生成树:一个连通图最小的连通子图。有n个顶点的连通图的生成树有n个顶点和n-1条边
简单路径:路径上的顶点不重复
回路:路径上的第一个顶点和最后一个顶点重合,称为回路
3、图的抽象数据类型
① 数据集合
数据集合由一组顶点{v}和一组边{e}集合组成,当为带权图时,还包含边上的权集合{w}
② 操作集合
//初始化图
Initiate(G);
//插入顶点
InsertVertex(G,vertex);
//插入边
InsertEdge(G,V1,V2,weight);
//删除边
DeleteEdge(G,V1,V2)
//删除顶点
DeleteVertex(G,vertex);
//取第一个领接顶点
GetFirstVex(G,int,V1,V2);
//取下一个领接顶点
GetNextVex(G,int,V1,V2);
//遍历
DepthFirstSearch(G);
二、图的存储结构
1、图的邻接矩阵存储结构
适用于稠密矩阵,当为稠密矩阵时最高效
顶点信息用一维数组存储,边信息的邻接矩阵用二维数组存储,无向图的邻接矩阵一定是对称矩阵。有向图一般非对称。
① 无向图和其邻接矩阵
考试写法如下:
② 带权无向图和其邻接矩阵
自己和自己为0,非邻接顶点为∞,权为权值
③ 有向图和其邻接矩阵
④ 带权有向图和其邻接矩阵
2、图的邻接表存储结构
适合稀疏矩阵,为稀疏矩阵时更有效
将稀疏矩阵存储在行指针数组结构的三元组链表中
三、图的实现
1、邻接矩阵存储结构图的操作实现
① 结点结构体
#inclede"SeqList.h"
typedef struct{SeqList vertices;//存放顶点的顺序表int edge[MaxVertices][MaxVertices];//存放边的邻接矩阵int numOfEdges;//边的条数
}AdjMGraph;
② 初始化
void Initiate(AdjMGraph *G,int n){int i,j;for(i=0;i<n;i++){for(j=0;j<n;j++){if(i==j) G->edge[i][j] = 0;else G->edge[i][j] = MaxWeight;//表示无穷大}G->numOfEdges = 0;ListInitiate(&G->Vertices);}
③ 插入顶点
void InsertVertex(AdjMGraph *G,DataType vertex){ListInsert(&G->Vertices,G->Vertices.size,vertex);
}
④ 插入边
void InsertEdge(AdjMGraph *G,int v1,int v2,int weight){if(v1<0 || v1 >= G->Vertives.size || v2<0 || v2>=G->Vertices.size){printf("参数v1或v2越界出错!\n");return;}G->edge[v1][v2]=weight;G->numOfEdges++;
}
⑤ 删除边
void DeleteEdge(AdjMGraph *G,int v1,int v2){if(v1<0 || v1>=G->Vertices.size || V1==V2){printf("参数v1或v2出错!\n");return;}if(G->edge[v1][v2]==MaxWeight||v1==v2){printf("该边不存在!\n");return;}G->edge[v1][v2]=MaxWeight;G->numOfEdges--;
}
⑦ 取第一个邻接顶点
int GetFirstVex(AdjMGraph G,int v){int col;if(v<0 || V>= G.Vertices.size){printf("参数v1越界出错");return -1;}for(col=0;col<G.Vertices.size;col++)if(G.edge[v][col]>0 && G.edge[v][col]<MaxWeight) return col;return -1;
}
⑧ 取下一个邻接结点
int GetNextVex(AdjMGraph G,int v1,int v2){int col;if(v1<0 || v1>=G.Vertices.size || V2<0 || V2>=G.Vertices.size){printf("参数v1或v2越界出错!\n");return -1;}for(col=v2+1;col<G.Vertices.size;col++)if(G.edge[v1][col]>0 && G.edge[v1][col]<MaxWeight) retutn col;return -1;
}
2、创建图函数
typedef struct{int row;//行int col;//列int weight;//权值
}RowColWeight;void GreatGraph(AdjMGraph *G,DataType V[],int n,RowColWeight E[],int e){int i,k;Initiate(G,n);for(i=0;i<n;i++)InsertVertex(G,V[i]);//插入顶点for(k=0;k<e;k++)InsertEdge(G,E[K].row,E[k].col.E[k].weight);//插入边
}
3、邻接表存储结构图的操作实现
① 邻接表的存储结构
typedef struct Node{int dest;//邻接边弧头顶点序号struct Node *next;
}Edge;
typedef struct{DataType data;//顶点数据元素int source;//邻接边弧尾顶点序号Edge *adj;//邻接边的头指针
}AdjHeight;
typedef struct{AdjLHeight a[MaxVertices];//邻接表数组int numOfVerts;//顶点个数int numOfEdges;//边个数
}AdjLGraph;
② 初始化
AdjInitiate(AdjLGraph *G){int i;G->numOfVerts=0;G->numOfEdfes=0;for(i=0;i<MaxVertices;i++){G->a[i].source = i;G->a[i].adj = NULL;}
}
③ 插入顶点
void InsertVertex(adjLGraph *G,int i,DataType vertex){if(i>=0 && i<Maxvertices){G->a[i].data=vertex;G->numOfVerts++;}else printf("顶点越界");
}
④ 插入边
void InsertEdge(AdjLGraph *G,int v1,int v2){Edge *p;if(v1<0 || v1>=G->numOfVerts || v2<0 || v2 >= G->numOfVerts){printf("参数v1或v2越界出错!");return;}p = (Edge *)malloc(sizeof(Edge));p->dest = v2;p->next = G->a[v1].adj;G->a[v1].adj = p;G->numOfEdges++;
}
⑤ 删除边
void DeleteEdge(AdjLGraph *G,int v1,int v2){Edge *curr,*pre;if(v1<0 || v1>= G->numOfVerts || v2<0 || v2>=G->numOfVerts){printf("参数v1或v2越界出错!");return;}pre = NULL;curr = G->a[v1].adj;while(curr != NULL && curr->dest != v2){pre = curr;curr = curr->next;}if(curr!=NULL && curr->dest !=v2){pre = curr;curr = G->a[v1].adj;while(curr!=NULL && curr->dest != v2){pre = curr;curr = curr->next;}if(curr != NULL && curr->dest == v2 && pre ==NULL){G->a[v1].adj=crtt->next;free(curr);G->numOfEdges--;}else if(curr != NULL && curr->dest == v2 && pre != NULL){pre->next = curr->next;free(curr);G->numOfEfges--;}elseprintf("边<v1,v2>不存在!")}
四、图的遍历
1、图的遍历关键点
- 图无首尾之分,要指定访问的第一个结点
- 设计要考虑遍历路径为回路的情况,避免死循环
- 要使一个顶点的所有邻接顶点按照某种次序都被访问到
2、图的深度优先遍历
顺着顶点一直找邻接结点,然后再返回到顶点,再找他的邻接结点一直顺着找,他没有就顺着他的邻接结点找
关键:在图的所有邻接顶点中,每次都在访问完当前顶点后,首先访问当前顶点的第一个邻接顶点。
① 访问顶点v并标记顶点v为已访问
② 查找顶点v的第一个邻接顶点w
③ 若顶点v的邻接顶点w存在,则继续执行,否则算法结束
④ 若顶点w尚未被访问,则深度优先遍历递归访问顶点w
⑤ 查找顶点v的w邻接顶点的下一个邻接顶点w,转到步骤3
void DepthFSearch(AdjMGraph G,int v,int visited[],void Visit(DataType)){int w;Visit(G.Vertices.list[v]);visited[v]=1;w=GetFirstVex(G,v);while(w!=-1){if(!visited[w])DepthFSearch(G,w,visited,Visit);w=GetNextVex(G,v,w);}
}
3、图的广度优先遍历
顺着顶点先找完它的邻接结点,一层一层的寻找
关键:从指定顶点开始,按照到该顶点的路径长度由短到长的顺序,依次访问图中的其余顶点
① 访问初始顶点v并标记顶点v为已访问
② 顶点v入队列
③ 若队列非空,则继续执行,否则算法结束
④ 出队列取得队头顶点u
⑤ 查找顶点u的第一个邻接顶点w
⑥ 若顶点u的邻接顶点w不存在,则转到步骤③,否则循环执行
(a)若顶点w尚未被访问,则访问顶点w并标记顶点w为已访问
(b)顶点w入队列
(c)查找顶点u的w邻接顶点后的下一个邻接顶点w,转到步骤⑥
#include "SeqCQueue.h"//导入循环队列
void BroadFSearch(AdjMGraph G,int v,int visited[],void Visit(DataType item)){int u,w;SeqCQueue queue;Visit(G.Vertices.list[v]);visitrd[v]=1;QueueInitiate(&queue);QueueAppend(&queue,v);while(QueueNotEmpty(queue)){QueueDelete(&queue,&u);w=GetFirstVex(G,u);while(w!=-1){if(!visited[w]){Visit(G.Vertices.list[w]);visited[w]=1;QueueAppend(&queue,w);}w=GetNextVex(G,u,w);}}
}
五、最小生成树
1、生成树
一个有n个顶点的连通图的生成树是原图的极小连通子图,有以下特点
无论它的生成树的形状如何,一定是:n个顶点,n-1条边
删除生成树一条边,导致其不是连通图
增加生成树一条边,会存在回路
连通图的生成树可以有许多,不同寻找方法生成不同生成树
2、最小生成树
如果有n个顶点的无向连通图是带权图,则它所有生成树必有一棵权值总和最小,则称为最小生成树
- 最小生成树必须包含n个顶点
- 有且只有n-1条边
- 不存在回路
3、构成最小生成树的方法
① Prim(普里姆)算法
普里姆(Prim)算法是一某个顶点为起点,逐步找各顶点最小权值的边来构建最小生成树。
步骤:
- 以一个点为顶点,找和它连通权值最小的点,形成新树
- 找和刚才两个点形成的树连通权值最小的点,形成新树
- 依次循环,直到所有点都连通
② Kruskal(克鲁斯卡尔)算法
将所有边的权值按从小到大的顺序进行排序,然后先连通最小的边形成树,不能出现回路,直到形成最小生成树。
- 找权值最小的边,连通两点,形成树
- 重复上一步直到形成最小生成树
六、最短路径
即距离最短,权值总和最低,非带权图可视为权值皆为1
1、Dijkastra算法:从源点到各个顶点的最短路径
按路径长度递增的顺序逐步产生最短路径的构造方法(动态规划)
① 设置distance[],path[]
- distance[]:用来存放得到的从源点v到其余各顶点的最短距离数值
- path[]:用来存放得到的从源点v到其余各顶点的最短路径上到目标顶点的前一个顶点的下标
② 从源点v开始,找到到达邻接结点u的最短距离(存入distance),确定到达该点的前一个顶点为源点(存入path)
③ 找从源点v到u的邻接结点u1的最短路径(存入distance),确定(更新)到达该点的前一个顶点为源点(存入path)
④ 循环③,直到找完从源点到各个点的最短路径
2、Floyd算法:每对顶点间的最短路径
① 设置两个二维数组,weight和path
- weight存放每对顶点之间的最短路径
- path存放到目标顶点的前顶点的序号
② 具体如图
③ 解释
weight记录的是当前最短路径
找从源点v到u的邻接结点u1的最短路径(存入distance),确定(更新)到达该点的前一个顶点为源点(存入path)
④ 循环③,直到找完从源点到各个点的最短路径
2、Floyd算法:每对顶点间的最短路径
① 设置两个二维数组,weight和path
- weight存放每对顶点之间的最短路径
- path存放到目标顶点的前顶点的序号
② 具体如图
③ 解释
weight记录的是当前最短路径
Path记录的是这个点到另外一个点当前最短路径最后一个中间点
C语言《数据结构》(朱战立):图相关推荐
- 数据结构c语言版朱战立报告,数据结构(C语言版)
本书是Sedgewick彻底修订和重写的C算法系列的第一本.全书分为四部分,共16章.第一部分"基础知识"(第1-2章)介绍基本算法分析原理.第二部分"数据结构" ...
- 数据结构java语言描述朱战立_数据结构——树(Java语言描述)
树根:rootNode. 树只有一个树根. 节点:Node. 树上的所有节点. 子节点数组:Node[]. 数组代表每个节点的所有子节点 父节点:parentNode. 每个节点只有一个父节点. 2. ...
- 数据结构-使用c语言 朱战立 pdf,数据结构-使用C语言朱战立.ppt
教材:教材: 朱战立编著,数据结构朱战立编著,数据结构----使用使用 C C语言(第语言(第3 3版),西安交通大版),西安交通大 学出版社,学出版社,20032003年年 数数 据据 结结 构构 ...
- 数据结构使用c语言朱战立答案,数据结构使用C语言朱战立第2章课件
数据结构使用C语言朱战立第2章课件 前牙反颌和开颌的原因多由于不良喂养方式和吮指等不良习惯造成,也可因多颗乳磨牙过早缺失,迫使儿童用前牙咀嚼,下颌逐渐前伸移位造成. typedef struct No ...
- 用c语言线性表的链式表示实现,数据结构-使用C语言 朱战立第2章线性表的链式表示.ppt...
数据结构-使用C语言 朱战立第2章线性表的链式表示 * 循环链表(circular linked list) 循环链表是表中最后一个结点的指针指向头结点,使链表构成环状 特点:从表中任一结点出发均可找 ...
- 数据结构java朱战立pdf_数据结构使用C语言 朱战立,刘天时编著.pdf
第 章 绪 论 计算机是对各种各样数据进行处理的机器 .在计算机 中如何组织数据 ,如何处理数据 ,从 而如何更好地利用数据是计算机科学的基本研究 内容 .掌握数据在计算机 中的各种组织和处 理方法是 ...
- C语言《数据结构》(朱战立):树
数据结构:树 一.树 1.树的定义 由n个结点构成的集合,n=0称为空树,n=1的树只有一个结点,对于n>1的树T有: 最顶端的结点称为根节点,根结点无前驱结点 除根结点,其余结点被分为m个不相 ...
- 【Dev-c++】C语言数据结构课程设计——基于图的航班线路设计系统
目 录 需求分析1 概要设计2 详细设计3 调试分析9 运行结果11 参考文献12 附录13 一.需求分析 (1)输入的形式和输入值的范围: 首先构建带权的有向图,输入整数的顶点和边数.即城市的个数, ...
- C语言数据结构-第七章图-电大同步进度
第七章图 内容简介 图结构中结点之间的关系是任意的,每个元素都可以和其他任何元素相关,即元素之间是多对多的关系. 图作为一种非线性数据结构,被广泛应用于多个技术领域,例如系统工程.化学分析.统计力学. ...
最新文章
- xtrabackup 使用说明(续)
- neo4j 修改密码
- 2020已过大半,量子计算机发展如何了?
- php的Allowed memory size of 134217728 bytes exhausted问题解决办法
- 微型计算机工作最小时间单位,2010~2011学年第1学期微机原理2试卷A(答案)
- CDA数据分析师-LEVEL I考试-分享
- 为什么 Mac 适合编程?
- Matlab/Simulink-Boost电路双闭环仿真搭建
- UVA1153 顾客是上帝 Keep the Customer Satisfied(贪心)
- 《腾云点菜宝》项目总结
- android 蓝牙耳机 sco,Android:通过Sco蓝牙耳机播放声音
- PDF如何删除页面?批量删除不连续页的方法
- 学校对计算机教师的检查要求,计算机学院2015-2016学年第二学期期中教学检查方案...
- java多线程-线程的停止【interrupt】
- Android下拉列表框
- 怎样调整3dsMax中的样条曲线
- 常用软件整理(待更新)
- B. Lorry (贪心)
- 小程序之统计网页访问人数
- 论文阅读方法与技巧【教授经验】
热门文章
- 计算机网络培训考试,网管人员培训考试试题
- STM32控制步进电机:工作原理及库函数(标准库) / HAL库控制程序(不定期更新)
- 应聘时如何回答quot;你的期望薪资…
- 2 ai and machine learning for coders Laurence Moroney 学习笔记(二)chapter2 计算机视觉导论(Introduction to CV))
- CentOS7服务器搭建百度贴吧云签到
- 用于喵喵111111111111111111
- pandas读取excel-xlrd相关
- 【转】绿色便携版Lazarus的制作教程
- opentack neutron环境
- 语音识别维特比解码_自然语言处理之维特比算法