C语言数据结构:图

一、图的基本概念

1、图的定义

G=(V,E)

  • V{x|x∈某个数据元素集合}:表示顶点
  • E{(x,y)|x,y∈V}:表示路径,若指定Path(x,y),说明x到y是一条单向通路,若不指定则是无向的。

2、图的基本术语

  1. 顶点和边:图中结点称为顶点,两个顶点相关联,这称两顶点间有条边

  2. 有向图和无向图:<x,y>,<y,x>表示边有方向,(x,y)表示边无方向

  3. 无向完全图:在n个顶点的无向图中,任意两个顶点间有且只有一条边(n(n-1)/2条边)

  4. 有向完全图:在n个顶点的有向图中,任意两个顶点之间有且只有方向相反的两条边(n(n-1))

  5. 邻接顶点:一条边的两个点称为邻接顶点

  6. 顶点的度:指与某一顶点相关联的边的条数,有几条边就有多少度

  7. 路径:从一个顶点到另外一个顶点的序列

  8. 权:边的附带信息

  9. 路径长度:不带权的图,路径的长度就行路径上边的条数。带权的图,路径的长度,是边上权的总和

  10. 子图:G1={V1,E2}和G2{V2,E2},若V2∈V1,E2属于E1,则G2是G1的子图

  11. 连通图:无向图中,任意两个顶点都能连通

  12. 强连通图,有向图中,任意两个顶点都能连通

  13. 生成树:一个连通图最小的连通子图。有n个顶点的连通图的生成树有n个顶点和n-1条边

  14. 简单路径:路径上的顶点不重复

  15. 回路:路径上的第一个顶点和最后一个顶点重合,称为回路

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语言《数据结构》(朱战立):图相关推荐

  1. 数据结构c语言版朱战立报告,数据结构(C语言版)

    本书是Sedgewick彻底修订和重写的C算法系列的第一本.全书分为四部分,共16章.第一部分"基础知识"(第1-2章)介绍基本算法分析原理.第二部分"数据结构" ...

  2. 数据结构java语言描述朱战立_数据结构——树(Java语言描述)

    树根:rootNode. 树只有一个树根. 节点:Node. 树上的所有节点. 子节点数组:Node[]. 数组代表每个节点的所有子节点 父节点:parentNode. 每个节点只有一个父节点. 2. ...

  3. 数据结构-使用c语言 朱战立 pdf,数据结构-使用C语言朱战立.ppt

    教材:教材: 朱战立编著,数据结构朱战立编著,数据结构----使用使用 C C语言(第语言(第3 3版),西安交通大版),西安交通大 学出版社,学出版社,20032003年年 数数 据据 结结 构构 ...

  4. 数据结构使用c语言朱战立答案,数据结构使用C语言朱战立第2章课件

    数据结构使用C语言朱战立第2章课件 前牙反颌和开颌的原因多由于不良喂养方式和吮指等不良习惯造成,也可因多颗乳磨牙过早缺失,迫使儿童用前牙咀嚼,下颌逐渐前伸移位造成. typedef struct No ...

  5. 用c语言线性表的链式表示实现,数据结构-使用C语言 朱战立第2章线性表的链式表示.ppt...

    数据结构-使用C语言 朱战立第2章线性表的链式表示 * 循环链表(circular linked list) 循环链表是表中最后一个结点的指针指向头结点,使链表构成环状 特点:从表中任一结点出发均可找 ...

  6. 数据结构java朱战立pdf_数据结构使用C语言 朱战立,刘天时编著.pdf

    第 章 绪 论 计算机是对各种各样数据进行处理的机器 .在计算机 中如何组织数据 ,如何处理数据 ,从 而如何更好地利用数据是计算机科学的基本研究 内容 .掌握数据在计算机 中的各种组织和处 理方法是 ...

  7. C语言《数据结构》(朱战立):树

    数据结构:树 一.树 1.树的定义 由n个结点构成的集合,n=0称为空树,n=1的树只有一个结点,对于n>1的树T有: 最顶端的结点称为根节点,根结点无前驱结点 除根结点,其余结点被分为m个不相 ...

  8. 【Dev-c++】C语言数据结构课程设计——基于图的航班线路设计系统

    目 录 需求分析1 概要设计2 详细设计3 调试分析9 运行结果11 参考文献12 附录13 一.需求分析 (1)输入的形式和输入值的范围: 首先构建带权的有向图,输入整数的顶点和边数.即城市的个数, ...

  9. C语言数据结构-第七章图-电大同步进度

    第七章图 内容简介 图结构中结点之间的关系是任意的,每个元素都可以和其他任何元素相关,即元素之间是多对多的关系. 图作为一种非线性数据结构,被广泛应用于多个技术领域,例如系统工程.化学分析.统计力学. ...

最新文章

  1. xtrabackup 使用说明(续)
  2. neo4j 修改密码
  3. 2020已过大半,量子计算机发展如何了?
  4. php的Allowed memory size of 134217728 bytes exhausted问题解决办法
  5. 微型计算机工作最小时间单位,2010~2011学年第1学期微机原理2试卷A(答案)
  6. CDA数据分析师-LEVEL I考试-分享
  7. 为什么 Mac 适合编程?
  8. Matlab/Simulink-Boost电路双闭环仿真搭建
  9. UVA1153 顾客是上帝 Keep the Customer Satisfied(贪心)
  10. 《腾云点菜宝》项目总结
  11. android 蓝牙耳机 sco,Android:通过Sco蓝牙耳机播放声音
  12. PDF如何删除页面?批量删除不连续页的方法
  13. 学校对计算机教师的检查要求,计算机学院2015-2016学年第二学期期中教学检查方案...
  14. java多线程-线程的停止【interrupt】
  15. Android下拉列表框
  16. 怎样调整3dsMax中的样条曲线
  17. 常用软件整理(待更新)
  18. B. Lorry (贪心)
  19. 小程序之统计网页访问人数
  20. 论文阅读方法与技巧【教授经验】

热门文章

  1. 计算机网络培训考试,网管人员培训考试试题
  2. STM32控制步进电机:工作原理及库函数(标准库) / HAL库控制程序(不定期更新)
  3. 应聘时如何回答quot;你的期望薪资…
  4. 2 ai and machine learning for coders Laurence Moroney 学习笔记(二)chapter2 计算机视觉导论(Introduction to CV))
  5. CentOS7服务器搭建百度贴吧云签到
  6. 用于喵喵111111111111111111
  7. pandas读取excel-xlrd相关
  8. 【转】绿色便携版Lazarus的制作教程
  9. opentack neutron环境
  10. 语音识别维特比解码_自然语言处理之维特比算法