数据结构无向图
- 格式:doc
- 大小:28.50 KB
- 文档页数:4
数据结构——图图的定义和基本术语
定义是由一个顶点集V和一个顶点间的关系集合组成的数据结构
分类
有向图
无向图
基本术语
有(无)向网弧或边带权的图
子图
完全图含有e=n(n-1)/2条边的无向图
有向完全图含有e=n(n-1)条弧的有向图
稀疏图边或弧的个数<nlogn
稠密图边或弧的个数>=nlogn
度(入度+出度)
入度以顶点v为弧尾的弧的数目
出度以顶点v为弧头的弧的数目
路径长度路径上边的数目
连通图图中任意两个顶点之间都有路径相通
图的遍历
深度优先搜索DPS
类似于先序遍历
实质对每个顶点查找其邻接点的过程
广度优先搜索BFS实质通过边或弧找邻接点的过程
图的存储结构
邻接矩阵
有向图:对称统计第i行1的个数可得顶点i的出度
无向图:不对称统计第j列1的个数可得顶点j的入度
邻接表只存储图中已有的弧或边的信息
有向图的十字链表将有向图的邻接表和逆邻接表结合起来的一种链
图的应用
最小生成树
普里姆(Prim)算法
贪心算法
最短路径
Dijkstra算法
Floyd算法
拓扑排序
关键路径。
算法与数据结构课程设计报告系(院):计算机科学学院专业班级:教技1001姓名:李##学号: ******### 指导教师:***设计时间:2012.6.16 - 2012.6.24设计地点:4号楼2号机房目录一、设计方案 (1)二、实现过程以及代码 (2)三、测试 (20)四、结论和分析 (23)五、难点和收获 (23)一、 设计方案1.程序设计基本过程:拿到课程设计任务书,按照要求,需要设计有向图、有向网、无向图 、无向网四种图,以及邻接矩阵、邻接表两种数据存储结构,三层以上的显示菜单。
图的操作中又包含了有关线性表、栈和队列的基本操作。
由于显示菜单已给出,剩下的任务就是把函数写入其中。
2.程序流程图:预定义 定义结构体 定义变量 各种函数3.程序设计的原理:图的操作都是以两种存储结构为基础的:邻接矩阵存储结构和邻接表存储结构,如有向图,有向网,无向图,无向网的创建,其他的操作都是在四种图创建后才开始进行的。
所以,首先必须理解两种存储结构的定义。
图的邻接矩阵存储结构即图的数组表示法。
用两个数组分别存储数据元素(如顶点)的信息和数据元素之间的关系(如边或弧)的信息。
用邻接矩阵存储结构的图具有以下几点特征:(一):顶点数:vexnum ,边(弧)数:arcnum ,图的种类:kind ;(二):邻接矩阵:arcs(1顶点关系类型:adj 2相关信息:*info);(三):顶点向量(顶点名):vexs[];其优点是以二维数组表示有n 个顶点的图时,需存放n 个顶点的信息和n*n 条弧的信息存储量。
借助邻接矩阵容易判定任意两个顶点之间是否有边或弧相连,并容易求出各个顶点的度。
缺点是时间复杂度是O (n*n ),例如,构造一个具有n 个顶点和e 条边的无向网的时间复杂度为O (n*n+e*n )。
图的邻接表存储结构是图的一种链式存储结构。
对图中的每个顶点建立一个单链表,每个结点由三个域组成,邻接点域adjvex (弧尾在邻接表链表中的位序),链域nextarc (下一条弧),数据域info(权值)。
无向图最短路径算法设计在图论中,最短路径算法是解决图中两个顶点之间最短路径问题的关键算法。
无向图是一种由顶点和边组成的数据结构,其中边没有方向。
本文将介绍几种常用的无向图最短路径算法的设计与实现。
一、Dijkstra算法Dijkstra算法是解决单源最短路径问题的一种贪心算法。
它通过逐步确定起点到各个顶点的最短距离,从起点开始,每次选择最短距离的顶点,并更新与该顶点相邻的顶点的最短距离。
直到所有顶点都被访问过,得到起点到各个顶点的最短路径。
该算法的步骤如下:1. 初始化起点到各个顶点的距离为无穷大,起点到自身的距离为0。
2. 选择起点作为当前顶点,标记该顶点已被访问。
3. 更新当前顶点的邻居顶点的最短距离,如果经过当前顶点到达邻居顶点的距离小于邻居顶点当前已有的最短距离,则更新邻居顶点的最短距离。
4. 从未被访问的顶点中选择距离起点最近的顶点作为新的当前顶点,并标记该顶点已被访问。
5. 重复步骤3和步骤4,直到所有顶点都被访问过。
二、Floyd-Warshall算法Floyd-Warshall算法是解决任意两点最短路径问题的一种动态规划算法。
它通过逐步更新所有顶点之间的最短路径长度,得到任意两点之间的最短路径。
该算法的步骤如下:1. 初始化距离矩阵,其中顶点之间的距离已知的用实际距离表示,未知的用无穷大表示。
2. 逐步更新距离矩阵,对于每个顶点k,判断通过顶点k是否可以使得顶点i到顶点j的距离变小,如果可以,则更新距离矩阵中的对应值。
3. 重复步骤2,直到所有顶点之间的最短路径长度都得到更新。
三、Bellman-Ford算法Bellman-Ford算法是解决单源最短路径问题的一种动态规划算法。
它通过逐步更新起点到各个顶点的最短距离,得到起点到其他顶点的最短路径。
该算法的步骤如下:1. 初始化起点到各个顶点的距离为无穷大,起点到自身的距离为0。
2. 逐步更新起点到各个顶点的最短距离,对于每条边(u, v),如果通过边(u, v)的距离小于起点到顶点v的当前最短距离,则更新起点到顶点v的最短距离。
图1. 填空题⑴设无向图G中顶点数为n,则图G至少有()条边,至多有()条边;若G为有向图,则至少有()条边,至多有()条边。
【解答】0,n(n-1)/2,0,n(n-1)【分析】图的顶点集合是有穷非空的,而边集可以是空集;边数达到最多的图称为完全图,在完全图中,任意两个顶点之间都存在边。
⑵任何连通图的连通分量只有一个,即是()。
【解答】其自身⑶图的存储结构主要有两种,分别是()和()。
【解答】邻接矩阵,邻接表【分析】这是最常用的两种存储结构,此外,还有十字链表、邻接多重表、边集数组等。
⑷已知无向图G的顶点数为n,边数为e,其邻接表表示的空间复杂度为()。
【解答】O(n+e)【分析】在无向图的邻接表中,顶点表有n个结点,边表有2e个结点,共有n+2e个结点,其空间复杂度为O(n+2e)=O(n+e)。
⑸已知一个有向图的邻接矩阵表示,计算第j个顶点的入度的方法是()。
【解答】求第j列的所有元素之和⑹有向图G用邻接矩阵A[n][n]存储,其第i行的所有元素之和等于顶点i的()。
【解答】出度⑺图的深度优先遍历类似于树的()遍历,它所用到的数据结构是();图的广度优先遍历类似于树的()遍历,它所用到的数据结构是()。
【解答】前序,栈,层序,队列⑻对于含有n个顶点e条边的连通图,利用Prim算法求最小生成树的时间复杂度为(),利用Kruskal 算法求最小生成树的时间复杂度为()。
【解答】O(n2),O(elog2e)【分析】Prim算法采用邻接矩阵做存储结构,适合于求稠密图的最小生成树;Kruskal算法采用边集数组做存储结构,适合于求稀疏图的最小生成树。
⑼如果一个有向图不存在(),则该图的全部顶点可以排列成一个拓扑序列。
【解答】回路⑽在一个有向图中,若存在弧、、,则在其拓扑序列中,顶点vi, vj, vk的相对次序为()。
【解答】vi, vj, vk【分析】对由顶点vi, vj, vk组成的图进行拓扑排序。
第5章图●图的定义①图由顶点集V和边集E组成,记为G=(V,E),V(G)是图G中顶点的有穷非空集合,E(G)是图G中顶点之间变得关系集合,|V|表示顶点个数,也称图的阶,|E|表示边数(线性表和树都可以是空的,但图可以只有一个顶点没有边)②有向图:弧是顶点的有序对,记为<v,w>,v,w是顶点,v是弧尾,w是弧头,从顶点v到顶点w的弧。
无向图:边是顶点的无序对,记为(v,w)③简单图:一个图满足:不存在重复边;不存在顶点到自身的边。
多重图相对于简单图定义④完全图:无向图中,任意两顶点之间存在边,称为完全无向图。
N个顶点的无向完全图有n(n-1)/2条边。
在有向图中,任意两顶点之间存在方向相反的两条弧,称为有向完全图,N 个顶点的有向完全图有n(n-1)条边。
⑤连通图:在无向图中任意两顶点都是连通的。
无向图中的极大连通子图称为连通分量。
极大要求连通子图包含其所有的边和顶点,极小连通子图既要保持图连通,又要保持边数最少⑥在有向图中任意两顶点v,w,存在从顶点v到顶点w和从顶点w到顶点v两条路径,这种图称为强连通图。
有向图的极大强连通子图称为有向图的强连通分量。
⑦生成树:①包含图中所有顶点n,②生成树有n-1条边, ③任意两点连通。
对生成树而言,砍去一条边变成非连通图,加上一条边形成一个回路。
在非连通图中,连通分量的生成树构成了非连通图的生成森林。
⑧顶点的度:以该顶点为端点的边的数目。
无向图的全部顶点的度之和等于边数的两倍。
有向图的度等于出度和入度之和,入度是以该顶点为终点的有向边的数目,出度是以该顶点为起点的有向边的数目。
有向图的全部顶点的入度之和和出度之和相等且等于边数。
⑨图中每条边可以标上具有某种含义的数值,该数值称为边的权值。
带有权值的图称为网。
○10对于无向图G=(V, {E}),如果边(v,v’)∈E,则称顶点v,v’互为邻接点,即v,v’相邻接。
边(v,v’)依附于顶点v 和v’,或者说边(v, v’)与顶点v 和v’相关联。
离散数学中的图论基础知识讲解图论是离散数学中的一个重要分支,研究的是图的性质和图中的关系。
图论在计算机科学、网络科学、运筹学等领域有着广泛的应用。
本文将从图的基本概念、图的表示方法、图的遍历算法以及一些常见的图论问题等方面进行讲解。
一、图的基本概念图是由顶点和边组成的一种数学结构。
顶点表示图中的元素,边表示元素之间的关系。
图可以分为有向图和无向图两种类型。
1. 无向图:无向图中的边没有方向,表示的是两个顶点之间的无序关系。
如果两个顶点之间存在一条边,那么它们之间是相邻的。
无向图可以用一个集合V表示顶点的集合,用一个集合E表示边的集合。
2. 有向图:有向图中的边有方向,表示的是两个顶点之间的有序关系。
如果从顶点A到顶点B存在一条有向边,那么A指向B。
有向图可以用一个集合V表示顶点的集合,用一个集合E表示有向边的集合。
二、图的表示方法图可以用多种方式进行表示,常见的有邻接矩阵和邻接表两种方法。
1. 邻接矩阵:邻接矩阵是一个二维数组,其中的元素表示两个顶点之间是否存在边。
如果顶点i和顶点j之间存在边,那么矩阵的第i行第j列的元素为1;否则为0。
邻接矩阵适用于表示稠密图,但对于稀疏图来说,会造成空间浪费。
2. 邻接表:邻接表是一种链表的数据结构,用来表示图中的顶点和边。
每个顶点对应一个链表,链表中存储与该顶点相邻的顶点。
邻接表适用于表示稀疏图,节省了存储空间。
三、图的遍历算法图的遍历是指按照某一规则访问图中的所有顶点。
常见的图的遍历算法有深度优先搜索(DFS)和广度优先搜索(BFS)。
1. 深度优先搜索:深度优先搜索是一种递归的搜索算法。
从某个顶点出发,首先访问该顶点,然后递归地访问与它相邻的未访问过的顶点,直到所有的顶点都被访问过。
2. 广度优先搜索:广度优先搜索是一种迭代的搜索算法。
从某个顶点出发,首先访问该顶点,然后依次访问与它相邻的所有未访问过的顶点,再依次访问与这些顶点相邻的未访问过的顶点,直到所有的顶点都被访问过。
数学与计算机学院课程设计说明书课程名称: 数据结构与算法课程设计课程代码: 6014389 题目: 无向图的邻接矩阵存储结构年级/专业/班: 2010级软件4班学生姓名: 吴超学号: 312010*********开始时间: 2011 年 12 月 9 日完成时间: 2011 年 12 月 30 日课程设计成绩:指导教师签名:年月日数据结构课程设计任务书学院名称:数学与计算机学院课程代码:__6014389______ 专业:软件工程年级:2010一、设计题目无向图的邻接矩阵存储结构二、主要内容图是无向带权图,对下列各题,要求写一算法实现。
1)能从键盘上输入各条边和边上的权值;2)构造图的邻接矩阵和顶点集。
3)输出图的各顶点和邻接矩阵4)插入一条边5)删除一条边6)求出各顶点的度7)判断该图是否是连通图,若是,返回1;否则返回0.8)使用深度遍历算法,输出遍历序列。
三、具体要求及应提交的材料用C/C++语言编程实现上述内容,对每个问题写出一个算法实现,并按数学与计算机学院对课程设计说明书规范化要求,写出课程设计说明书,并提交下列材料:1)课程设计说明书打印稿一份2)课程设计说明书电子稿一份;3)源程序电子文档一份。
四、主要技术路线提示用一维数组存放图的顶点信息,二维数组存放各边信息。
五、进度安排按教学计划规定,数据结构课程设计为2周,其进度及时间大致分配如下:六、推荐参考资料[1] 严蔚敏,吴伟民.数据结构.清华大学出版社出版。
[2] 严蔚敏,吴伟民. 数据结构题集(C语言版) .清华大学出版社.2003年5月。
[3]唐策善,李龙澎.数据结构(作C语言描述) .高等教育出版社.2001年9月[4] 朱战立.数据结构(C++语言描述)(第二版本).高等出版社出版.2004年4月[5]胡学钢.数据结构(C语言版) .高等教育出版社.2004年8月指导教师签名日期年月日系主任审核日期年月日目录引言 (7)1 需求分析 (7)1.1任务与分析 (7)1.2测试数据 (8)2 概要设计 (8)2.1 ADT描述 (8)2.2程序模块结构 (9)2.3各功能模块 (11)3详细设计 (11)3.1类的定义 (11)3.2 初始化 (12)3.3 图的构建操作 (13)3.4 输出操作 (13)3.5 get操作 (14)3.6 插入操作 (14)3.7 删除操作 (15)3.8 求顶点的度操作 (15)3.10 判断连通操作 (17)3.11 主函数 (17)4 调试分析 (17)4.1 测试数据 (20)4.2调试问题 (20)4.3 算法时间复杂度 (20)4.4 经验和心得体会 (21)5用户使用说明 (21)6测试结果 (21)6.1 创建图 (21)6.2插入节点 (22)6.3 深度优先遍历 (22)6.4 求各顶点的度 (22)6.5 输出图 (23)6.6 判断是否连通 (23)6.7 求边的权值 (24)6.8 插入边 (24)6.9 删除边 (25)结论 (26)致谢 (27)摘要随着计算机的普及,涉及计算机相关的科目也越来越普遍,其中数据结构是计算机专业重要的专业基础课程与核心课程之一,为适应我国计算机科学技术的发展和应用,学好数据结构非常必要,然而要掌握数据结构的知识非常难,所以对“数据结构”的课程设计比不可少。
1.采用邻接矩阵(邻接表)存储,构造无向图(网)输入:顶点数、边数、顶点信息、边信息输出:图的顶点,图的边邻接矩阵(数组表示法)处理方法:用一个一维数组存储图中顶点的信息,用一个二维数组(称为邻接矩阵)存储图中各顶点之间的邻接关系。
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n 的方阵,定义为:如果(vi,vj)属于边集,则edges[i][j]=1,否则edges[i][j]=0。
邻接表存储的处理方法:对于图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(对于有向图则称为出边表),所有边表的头指针和存储顶点信息的一维数组构成了顶点表。
程序代码:#include<iostream>using namespace std;#define MAX_VERTEX_NUM 20 //最大顶点个数#define OK 1typedef int Status;//图的数组(邻接矩阵)存储表示typedef struct ArcCell { // 弧的定义int adj; // VRType是顶点关系类型。
// 对无权图,用1或0表示相邻否;// 对带权图,则为权值类型。
int *info; // 该弧相关信息的指针} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedef struct { // 图的定义char vexs[MAX_VERTEX_NUM];//顶点向量AdjMatrix arcs; // 邻接矩阵int vexnum, arcnum; // 图的当前顶点数、弧数} MGraph;int LocateV ex(MGraph G, char v){int a;for (int i = 0; i <= G.vexnum; i++){if (G.vexs[i] == v)a= i;}return a;}Status CreateUDN(MGraph &G) { //采用邻接矩阵表示法,构造无向网Gint i, j, k, w;char v1, v2;cout <<"输入顶点数,边数:"<< endl;cin >> G.vexnum >> G.arcnum;//IncInfo为0,表示各弧无信息cout <<"各顶点分别为:"<< endl;for (i = 0; i<G.vexnum; i++)cin >> G.vexs[i]; //构造顶点向量for (i = 0; i<G.vexnum; i++) //初始化邻接矩阵for (j = 0; j<G.vexnum; j++){G.arcs[i][j].adj =NULL;}cout <<"顶点信息、边信息:"<< endl;for (k = 0; k<G.arcnum; k++) { //构造邻接矩阵cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值i = LocateV ex(G, v1); j = LocateV ex(G, v2);G.arcs[i][j].adj = w;G.arcs[j][i] = G.arcs[i][j];} return OK;} //CreateUDN (p162 算法7.2)Status printf1(MGraph G){cout <<"该图的顶点分别为:";for (int i = 0; i<G.vexnum; i++)cout << G.vexs[i] <<"";return OK;}Status printf2(MGraph G){cout <<"该图的边为:";for (int i = 1; i<G.vexnum; i++) //初始化邻接矩阵for (int j = 0; j<i; j++){if (G.arcs[i][j].adj !=NULL)cout << G.vexs[j]<< G.vexs[i] <<"," ;}return OK;}int main(){MGraph G;CreateUDN(G);printf1(G);cout << endl;printf2(G);cout << endl;system("pause");return 0;}。
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 100000 //最大值∞
#define MAX_VERTEX_NUM 20 //最大顶点个数
typedef struct mygraph{
char vexs[MAX_VERTEX_NUM]; //顶点向量
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexnum, arcnum; //图的当前顶点和弧数
}MGraph;
typedef struct myedge{
int adjvex;
int endvex;
int lowcost;
} closedge[MAX_VERTEX_NUM];
void CreateUDN(MGraph &G) ; //创建无向网络
int LocateVex(MGraph G, char v); //结点的在顶点向量中的下标
void PrintUDN(MGraph G); //输出存储结构示意图
void MiniSpanTree_PRIM(MGraph G,closedge &minedge);//求最小生成树的算法void PrintMinEdge(MGraph G,closedge minedge); //输出最小生成树的边
int main()
{
MGraph G;//定义一个图的变量
closedge minedge;
CreateUDN(G);
printf("该图的邻接矩阵存储示意图如下:\n");
PrintUDN(G);
printf("\n");
MiniSpanTree_PRIM(G,minedge);
printf("该图生成树的边如下:\n");
PrintMinEdge(G,minedge);
printf("\n");
return 0;
}
void CreateUDN(MGraph &G)
{ int i,j,k,m;
char v1,v2;
char ch;
printf("请输入G.vexnum 和 G.arcnum:\n" );
scanf("%d %d",&G.vexnum,&G.arcnum);
while ((ch=getchar())!='\n'); /*** 为了去掉后面的回车符好 ***/ for (i=0; i<G.vexnum; i++ ) //输入所有的顶点,一行一个顶点
{
scanf("%c",&G.vexs[i]);
} // 构造顶点向量
while ((ch=getchar())!='\n') ;
for (i=0; i<G.vexnum; ++i ) // 初始化所有边之间的距离都是无穷for (j=0; j<G.vexnum; ++j )
{
G.arcs[i][j] = INFINITY;
}
for (k=0; k<G.arcnum; ++k )
{ // 构造邻接矩阵
scanf("%c%c %d", &v1,&v2,&m);
while ((ch=getchar())!='\n') ;
// 确定v1和v2在G中位置
i = LocateVex(G, v1);
j = LocateVex(G, v2);
G.arcs[i][j]=m; // 在矩阵中设置边(v1,v2),想通则值为1
G.arcs[j][i]=m; // 置(v1,v2)的对称边(v2,v1)
}
for(i=0;i<G.arcnum; ++i)
G.arcs[i][i]=0;
} // End_CreateUDN
int LocateVex(MGraph G, char v)
{int i;
for(i=0;i<G.vexnum;i++)
if(v==G.vexs[i])break;
return(i);
}
void PrintUDN(MGraph G)
{int i,j;
printf(" ");
for(i=0;i<G.vexnum;i++)
printf(" %c ",G.vexs[i]);
printf("\n");
for(i=0;i<G.vexnum;i++)
{printf("%c",G.vexs[i]);
for(j=0;j<G.vexnum;j++)
if(G.arcs[i][j] == INFINITY) printf(" *"); else printf(" %2d",G.arcs[i][j]);
printf("\n");
}
}
void MiniSpanTree_PRIM(MGraph G,closedge &minedge) {
int i,j,k,z;
int temp;
int currentmin;
k=0;
for ( j=1; j<G.vexnum; ++j )// 辅助数组初始化
{
minedge[j-1].adjvex=k;
minedge[j-1].endvex =j;
minedge[j-1].lowcost=G.arcs[k][j];
}
for (i=0; i<G.vexnum-1; ++i)
{ currentmin=minedge[i].lowcost;
k=i;
for(j=i+1;j<G.vexnum-1;j++)//选择最小的边
{
if(minedge[j].lowcost<currentmin)
{
currentmin=minedge[j].lowcost;
k=j;
}
}
{//第k个元素与第i个进行交换
temp=minedge[i].adjvex;
minedge[i].adjvex=minedge[k].adjvex;
minedge[k].adjvex=temp;
temp=minedge[i].endvex;
minedge[i].endvex=minedge[k].endvex;
minedge[k].endvex=temp;
temp=minedge[i].lowcost;
minedge[i].lowcost=minedge[k].lowcost;
minedge[k].lowcost=temp;
}
for (j=i+1; j<G.vexnum-1; ++j)
{
z=minedge[i].endvex ;//z为找到的新顶点
k=minedge[j].endvex;
if(k!=z)
{
if (G.arcs[z][k] < minedge[j].lowcost)
{
minedge[j].adjvex=z;
minedge[j].lowcost=G.arcs[z][k];
}
}
}
}
} // MiniSpanTree
void PrintMinEdge(MGraph G,closedge minedge)
{int i,j,k;
for(i=0;i<G.vexnum-1;i++)
{ j=minedge[i].adjvex;
k= minedge[i].endvex;
printf("%c%c %d",G.vexs[j],G.vexs[k],minedge[i].lowcost); printf("\n");
}
}。