严蔚敏数据结构 chapter7 图

合集下载

数据结构严蔚敏PPT(完整版)

数据结构严蔚敏PPT(完整版)
算法(Algorithm):是对特定问题求解方法(步骤)的一种 描述,是指令的有限序列,其中每一条指令表示一个或 多个操作。
算法具有以下五个特性
① 有穷性: 一个算法必须总是在执行有穷步之后结 束,且每一步都在有穷时间内完成。
② 确定性:算法中每一条指令必须有确切的含义。 不存在二义性。且算法只有一个入口和一个出口。
图状结构
一般线性表 栈和队列 串 数组 广义表 一般树 二叉树 有向图 无向图
图1-5 数据逻辑结构层次关系图
1.1.5 数据类型
数据类型(Data Type):指的是一个值的集合和定 义在该值集上的一组操作的总称。
数据类型是和数据结构密切相关的一个概念。 在C 语言中数据类型有:基本类型和构造类型。
问题:必须先运行依据算法编制的程序;依赖软硬 件环境,容易掩盖算法本身的优劣;没有实际价值。 事前分析:求出该算法的一个时间界限函数。
与此相关的因素有: – 依据算法选用何种策略; – 问题的规模; – 程序设计的语言; – 编译程序所产生的机器代码的质量; – 机器执行指令的速度; 撇开软硬件等有关部门因素,可以认为一个特定算
K={k1, k2, …, k9} R={ <k1, k3>,<k1, k8>,<k2, k3>,<k2, k4>,<k2, k5>,<k3, k9>, <k5, k6>,<k8, k9>,<k9, k7>,<k4, k7>,<k4, k6> } 画出这逻辑结构的图示,并确定那些是起点,那些是终点
数据元素之间的关系可以是元素之间代表某种含义 的自然关系,也可以是为处理问题方便而人为定义的 关系,这种自然或人为定义的 “关系”称为数据元素 之间的逻辑关系,相应的结构称为逻辑结构。

数据结构严蔚敏7章图ppt课件

数据结构严蔚敏7章图ppt课件

InfoType *info;
}VNode,AdjList[MAX_V];
}ArcNode;
typedef struct //图的邻接表类型
{ AdjList vertices; //存储图中所有顶点的数组
int vexnum,arcnum; //存储图的顶点数目和边(弧)的数目
int kind; //图的种类标志
返回
表结点
adjvex nextarc info
表头结点
data firstarc
typedef struct ArcNode typedef struct
{ int adjvex;
{ VertexType data;
struct ArcNode *nextarc; ArcNode *firstarc;
}ArcCell,AdjMatrix[MAX_V][MAX_V];
typedef struct
{ VertexType vex[MAX_V]; //顶点信息数组(如顶点编号等)
AdjMatrix arcs;
//图的邻接矩阵
int vexnum,arcnum; //图的顶点数和边(弧)的数目
GraphKind kind;//图的种类标志
A CB F DE G (a) 有向图G1
A BC D EF (b) 无向图G2
返回
2 几个常用术语 可以证明,对于具有n个顶点的无向图的边和具有n个
顶点的有向图的弧的最大数目分别为n(n-1)/2和n(n-1)。 称具有n(n-1)/2条边的无向图为完全图(completed
grahp)。 称具有n(n-1)条弧的有向图为完全有向图 称边或弧的数目e<nlogn的图为稀疏图(sparse

数据结构严蔚敏PPT完整版2024新版

数据结构严蔚敏PPT完整版2024新版

选择排序的基本思想
在未排序序列中找到最小(或最大)元素,存放到排序 序列的起始位置,然后,再从剩余未排序元素中继续寻 找最小(或最大)元素,然后放到已排序序列的末尾。 以此类推,直到所有元素均排序完毕。
交换排序和归并排序
交换排序的基本思想
通过不断地交换相邻的两个元素(如果它们的顺序错 误)来把最小的元素“浮”到数列的一端。具体实现 时,从第一个元素开始,比较相邻的两个元素,如果 前一个比后一个大,则交换它们的位置;每一对相邻 元素做同样的工作,从开始第一对到结尾的最后一对 ;这步做完后,最后的元素会是最大的数;针对所有 的元素重复以上的步骤,除了最后一个;持续每次对 越来越少的元素重复上面的步骤,直到没有任何一对 数字需要比较。
归并排序的基本思想
将两个或两个以上的有序表合并成一个新的有序表。具 体实现时,把长度为n的输入序列分成两个长度为n/2 的子序列;对这两个子序列分别采用归并排序;将两个 排序好的子序列合并成一个最终的排序序列。
查找的基本概念和方法
查找的定义
根据给定的某个值,在查找表中确定 一个其关键字等于给定值的数据元素 的过程或操作。
数组的定义和基本操作
数组的定义
数组(Array)是由相同类型的元素( element)的集合所组成的数据结构 ,分配一块连续的内存来存储。利用 元素的索引(index)可以计算出该 元素对应的存储位置。
数组的基本操作
数组的基本操作包括数组的创建、数 组的初始化、数组的访问、数组的遍 历、数组的排序和数组的查找等。
顺序表的基本操作实现
包括插入、删除、查找等操作,时间复杂度为 O(n)。
顺序表的特点
支持随机访问,存储密度高,但插入和删除操作需要移动大量元素。

《数据结构(C语言版 第2版)》(严蔚敏 著)第七章练习题答案

《数据结构(C语言版 第2版)》(严蔚敏 著)第七章练习题答案

《数据结构(C语言版第2版)》(严蔚敏著)第七章练习题答案第7章查找1.选择题(1)对n个元素的表做顺序查找时,若查找每个元素的概率相同,则平均查找长度为()。

A.(n-1)/2B.n/2C.(n+1)/2D.n答案:C解释:总查找次数N=1+2+3+…+n=n(n+1)/2,则平均查找长度为N/n=(n+1)/2。

(2)适用于折半查找的表的存储方式及元素排列要求为()。

A.链接方式存储,元素无序B.链接方式存储,元素有序C.顺序方式存储,元素无序D.顺序方式存储,元素有序答案:D解释:折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

(3)如果要求一个线性表既能较快的查找,又能适应动态变化的要求,最好采用()查找法。

A.顺序查找B.折半查找C.分块查找D.哈希查找答案:C解释:分块查找的优点是:在表中插入和删除数据元素时,只要找到该元素对应的块,就可以在该块内进行插入和删除运算。

由于块内是无序的,故插入和删除比较容易,无需进行大量移动。

如果线性表既要快速查找又经常动态变化,则可采用分块查找。

(4)折半查找有序表(4,6,10,12,20,30,50,70,88,100)。

若查找表中元素58,则它将依次与表中()比较大小,查找结果是失败。

A.20,70,30,50B.30,88,70,50C.20,50D.30,88,50答案:A解释:表中共10个元素,第一次取⎣(1+10)/2⎦=5,与第五个元素20比较,58大于20,再取⎣(6+10)/2⎦=8,与第八个元素70比较,依次类推再与30、50比较,最终查找失败。

(5)对22个记录的有序表作折半查找,当查找失败时,至少需要比较()次关键字。

A.3B.4C.5D.6答案:B解释:22个记录的有序表,其折半查找的判定树深度为⎣log222⎦+1=5,且该判定树不是满二叉树,即查找失败时至多比较5次,至少比较4次。

(6)折半搜索与二叉排序树的时间性能()。

数据结构(严蔚敏)第7章 PPT课件

数据结构(严蔚敏)第7章 PPT课件

B A
F
2019年12月13日星期五
C
F
E
D 若无向图为非连通图, 则图中各个极大连通
E
子图称作此图的连通
分量。
第16页
对有向图,若任意两个顶点之间都存在
一条有向路径,则称此有向图为强连通图。
否则,其各个强连通子图称作它的 强连通分量。
A
A
B
EB
E
CF
2019年12月13日星期五
第17页
CF
假设一个连通图有 n 个顶点和 e 条边, 其中 n-1 条边和 n 个顶点构成一个极小连 通子图,称该极小连通子图为此连通图的 生成树。
2019年12月13日星期五
E 顶点的出度: 以顶点v 为弧尾的弧的数目;
顶点的入度: 以顶点v 为弧头的弧的数目。
顶点的度(TD)= 出度(OD)+入度(ID)
第14页
设图G=(V,{VR})中的一个顶点序列
{ u=vi,0,vi,1, …, vi,m=w}中,(vi,j-1,vi,j)VR 1≤j≤m, 则称从顶点u 到顶点w 之间存在一条路径。
2019年12月13日星期五
7.1 图的定义与术语
7.2 图的存储表示
7.3 图的遍历
7.4 最小生成树
7.5 重(双)连通图和关节点
7.6 两点之间的最短路径问题
7.7 拓扑排序
2019年12月13日星期五
7.8 关键路径 第6页
7.1 图的定义与术语
图的结构定义:
图是由一个顶点集 V 和一个弧集 R构成 的数据结构。
struct ArcBox *hlink, *tlink;
} VexNode;
2019年12月13日星期五

数据结构第七章--图(严蔚敏版)

数据结构第七章--图(严蔚敏版)
9个顶点 个顶点
8个顶点的无向图最多有 条边且该图为连通图 个顶点的无向图最多有28条边且该图为连通图 个顶点的无向图最多有 连通无向图构成条件:边 顶点数 顶点数-1)/2 顶点数*(顶点数 连通无向图构成条件 边=顶点数 顶点数 顶点数>=1,所以该函数存在单调递增的单值反 顶点数 所以该函数存在单调递增的单值反 函数,所以边与顶点为增函数关系 所以28个条边 函数 所以边与顶点为增函数关系 所以 个条边 的连通无向图顶点数最少为8个 所以28条边的 的连通无向图顶点数最少为 个 所以 条边的 非连通无向图为9个 加入一个孤立点 加入一个孤立点) 非连通无向图为 个(加入一个孤立点
28
无向图的邻接矩阵为对称矩阵
2011-10-13
7.2
图的存储结构
Wij 若< vi,vj > 或<vj,v i > ∈E(G)
若G是网(有权图),邻接矩阵定义为 是网(有权图), ),邻接矩阵定义为
A [ i,j ] = , 0或 ∞
如图: 如图:
V1
若其它
V2
3 4
2
V3
2011-10-13
C
A
B
D 2011-10-13 (a )
3
Königsberg七桥问题
• Königsberg七桥问题就是说,能否从某点出发 通过每桥恰好一次回到原地?
C
C
A B

A D
B
D (a)
2011-10-13
(b)
4
第七章 图
7.1 图的定义 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图及其应用 7.6 最短路径
2011-10-13

数据结构严蔚敏PPT(完整版)

数据结构严蔚敏PPT(完整版)
排序算法的时间复杂度
时间复杂度是衡量算法效率的重要指标,常见的 排序算法的时间复杂度有O(n^2)、O(nlogn)、 O(n)等。
查找的基本概念和算法
查找的基本概念
查找是指在一个已经有序或部分 有序的数据集合中,找到一个特 定的元素或一组元素的过程。
常见查找算法
常见的查找算法包括顺序查找 、二分查找、哈希查找等。
先进先出(FIFO)的数据 处理。
并行计算中的任务调度。
打印机的打印任务管理。
二叉树的层序遍历(宽度 优先搜索,BFS)。
04
树和图
树的基本概念和性质
树的基本概念
树是一种非线性数据结构,由节 点和边组成,其中节点表示实体 ,边表示实体之间的关系。
树的性质
树具有层次结构,节点按照层次 进行排列,每个节点最多只能有 一个父节点,除了根节点外。
isEmpty:判断队列是否为空。
enqueue:向队尾添加一个元素。
front 或 peek:查看队首元素。
dequeue:删除队首的元素。
栈和队列的应用
栈的应用 后进先出(LIFO)的数据处理。
括号匹配问题。
栈和队列的应用
队列的应用
深度优先搜索(DFS)。 表达式求值。
01
03 02
栈和队列的应用
数据结构严蔚敏ppt( 完整版)
contents
目录
• 绪论 • 线性表 • 栈和队列 • 树和图 • 排序和查找 • 数据结构的应用案例分析
01
绪论
数据结构的基本概念
总结词
数据结构是计算机存储和组织数据的方式,是算法和数据操 作的基础。
详细描述
数据结构是计算机科学中研究数据的组织和存储方式的学科 ,它决定了数据在计算机中的表示和关系。数据结构不仅包 括数据的逻辑结构,还涉及到数据的物理存储方式以及数据 的操作方式。

数据结构 C语言版(严蔚敏版)第7章 图

数据结构 C语言版(严蔚敏版)第7章 图
data Fout
1
2
4
1
e6 2 4
2016/11/7
29
7.3 图的遍历



从已给的连通图中某一顶点出发,沿着一 些边访遍图中所有的顶点,且使每个顶点 仅被访问一次,就叫做图的遍历 ( Graph Traversal )。 图中可能存在回路,且图的任一顶点都可 能与其它顶点相通,在访问完某个顶点之 后可能会沿着某些边又回到了曾经访问过 的顶点。 为了避免重复访问,可设置一个标志顶点 是否被访问过的辅助数组 visited [ ]。
2
1 2
V2
V4
17
结论:



无向图的邻接矩阵是对称的; 有向图的邻接矩阵可能是不对称的。 在有向图中, 统计第 i 行 1 的个数可得顶点 i 的出度,统计第 j 行 1 的个数可得顶点 j 的入度。 在无向图中, 统计第 i 行 (列) 1 的个数可得 顶点i 的度。
2016/11/7

18

2
邻接表 (出度表)
adjvex nextarc
data firstarc
0 A 1 B 2 C
2016/11/7
1 0 1
逆邻接表 (入度表)
21

网络 (带权图) 的邻接表
6 9 0 2 1 C 2 8 3 D
data firstarc Adjvex info nextarc
2016/11/7
9



路径长度 非带权图的路径长度是指此路径 上边的条数。带权图的路径长度是指路径 上各边的权之和。 简单路径 若路径上各顶点 v1,v2,...,vm 均不 互相重复, 则称这样的路径为简单路径。 回路 若路径上第一个顶点 v1 与最后一个 顶点vm 重合, 则称这样的路径为回路或环。

数据结构-清华大学严蔚敏PPT

数据结构-清华大学严蔚敏PPT
③ 可行性: 一个算法是能行的。即算法描述的操作 都可以通过已经实现的基本运算执行有限次来实现。
④ 输入: 一个算法有零个或多个输入,这些输入 取自于某个特定的对象集合。
⑤ 输出: 一个算法有一个或多个输出,这些输出 是同输入有着某些特定关系的量。
一个算法可以用多种方法描述,主要有:使用自 然语言描述;使用形式语言描述;使用计算机程序设计 语言描述。
初始化赋值查找修改插入删除求长度等初始化赋值查找修改插入删除求长度等以下将对几种主要的操作进行讨论以下将对几种主要的操作进行讨论statusinitsqlistsqliststatusinitsqlistsqlistlelemarrayelemtypelelemarrayelemtypemallocmaxsizesizeofelemtypemallocmaxsizesizeofelemtypereturnerrorreturnerrorreturnokreturnok在线性表在线性表i1i1i1i1个位置上插入一个新结点个位置上插入一个新结点使其成使其成为线性表为线性表i1i1i1i1将线性表将线性表个结点后移一个位个结点后移一个位将结点将结点插入到结点插入到结点i1i1之后之后线性表长度加线性表长度加算法描述算法描述statusinsertsqlistsqliststatusinsertsqlistsqlistelemtypeelemtypei0illength1returnerrori0illength1returnerror线性表溢出线性表溢出returnerrorlelemarrayj1lelemarrayj
算法与数据结构
教材:《数据结构 (C 语言版 ) 》。严蔚敏,吴伟民

著。清华大学出版社。
参考文献:
1 《数据结构》 。张选平,雷咏梅 编, 严蔚敏 审。 机械工业出版社。

数据结构严蔚敏ppt课件

数据结构严蔚敏ppt课件

数据结构(严蔚敏)版●资料上传者:安徽大学研究生●资料使用范围:各大学考研及本科教学●欢迎报考安徽大学研究生●“星光考研书屋”祝您学习愉快[学习目标]掌握线性表的顺序存储结构和抽象数据类型中定义的每一种操作的含义,在顺序存储方式下每一种操作的具体实现和相应的时间复杂度;掌握链接存储的概念,线性表的单、双链接存储结构,对它们进行插入和删除结点的方法,循环单、双链表和带表头附加结点的单、双链表的结构和操作特点;掌握每一种线性表操作在由动态结点构成的单链表上具体实现的算法以及相应的时间复杂度。

2第2章线性表线性结构是最常用、最简单的一种数据结构。

而线性表是一种典型的线性结构。

其基本特点是线性表中的数据元素是有序且是有限的。

在这种结构中:① 存在一个唯一的被称为“第一个”的数据元素;② 存在一个唯一的被称为“最后一个”的数据元素;③ 除第一个元素外,每个元素均有唯一一个直接前驱;④ 除最后一个元素外,每个元素均有唯一一个直接后继。

32.1 线性表的逻辑结构线性表(Linear List ) :是由n(n ≧0)个数据元素(结点)a 1,a 2, …a n 组成的有限序列。

该序列中的所有结点具有相同的数据类型。

其中数据元素的个数n 称为线性表的长度。

当n=0时,称为空表。

当n>0时,将非空的线性表记作: (a 1,a 2,…a n ) a 1称为线性表的第一个(首)结点,a n 称为线性表的最后一个(尾)结点。

2.1.1 线性表的定义4a1,a2,…a i-1都是a i(2≦i≦n)的前驱,其中a i-1是a i的直接前驱;a i+1,a i+2,…a n都是a i(1≦i ≦n-1)的后继,其中a i+1是a i的直接后继。

2.1.2线性表的逻辑结构线性表中的数据元素a i所代表的具体含义随具体应用的不同而不同,在线性表的定义中,只不过是一个抽象的表示符号。

◆线性表中的结点可以是单值元素(每个元素只有一个数据项) 。

严蔚敏《数据结构(c语言版)习题集》答案第七章 图

严蔚敏《数据结构(c语言版)习题集》答案第七章 图

严蔚敏《数据结构(c语言版)习题集》答案第七章图第七章图7.14Status Build_AdjList(ALGraph &G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接表{InitALGraph(G);scanf("%d",&v);if(v<0) return ERROR; //顶点数不能为负G.vexnum=v;scanf("%d",&a);if(a<0) return ERROR; //边数不能为负G.arcnum=a;for(m=0;m<v;m++)G.vertices[m].data=getchar(); //输入各顶点的符号for(m=1;m<=a;m++){t=getchar();h=getchar(); //t为弧尾,h为弧头if((i=LocateVex(G,t))<0) return ERROR;if((j=LocateVex(G,h))<0) return ERROR; //顶点未找到p=(ArcNode*)malloc(sizeof(ArcNode));if(!G.vertices.[i].firstarc) G.vertices[i].firstarc=p;else{for(q=G.vertices[i].firstarc;q->nextarc;q=q->nextarc);q->nextarc=p;}p->adjvex=j;p->nextarc=NULL;}//whilereturn OK;}//Build_AdjList7.15//本题中的图G均为有向无权图,其余情况容易由此写出Status Insert_Vex(MGraph &G, char v)//在邻接矩阵表示的图G上插入顶点v {if(G.vexnum+1)>MAX_VERTEX_NUM return INFEASIBLE;G.vexs[++G.vexnum]=v;return OK;}//Insert_VexStatus Insert_Arc(MGraph &G,char v,char w)//在邻接矩阵表示的图G上插入边(v,w) {if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;if(i==j) return ERROR;if(!G.arcs[i][j].adj){G.arcs[i][j].adj=1;G.arcnum++;}return OK;}//Insert_ArcStatus Delete_Vex(MGraph &G,char v)//在邻接矩阵表示的图G上删除顶点v{n=G.vexnum;if((m=LocateVex(G,v))<0) return ERROR;G.vexs[m]<->G.vexs[n]; //将待删除顶点交换到最后一个顶点for(i=0;i<n;i++){G.arcs[i][m]=G.arcs[i][n];G.arcs[m][i]=G.arcs[n][i]; //将边的关系随之交换}G.arcs[m][m].adj=0;G.vexnum--;return OK;}//Delete_Vex分析:如果不把待删除顶点交换到最后一个顶点的话,算法将会比较复杂,而伴随着大量元素的移动,时间复杂度也会大大增加.Status Delete_Arc(MGraph &G,char v,char w)//在邻接矩阵表示的图G上删除边(v,w) {if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;if(G.arcs[i][j].adj){G.arcs[i][j].adj=0;G.arcnum--;}return OK;}//Delete_Arc7.16//为节省篇幅,本题只给出Insert_Arc算法.其余算法请自行写出.Status Insert_Arc(ALGraph &G,char v,char w)//在邻接表表示的图G上插入边(v,w) {if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=j;p->nextarc=NULL;if(!G.vertices[i].firstarc) G.vertices[i].firstarc=p;else{for(q=G.vertices[i].firstarc;q->q->nextarc;q=q->nextarc)if(q->adjvex==j) return ERROR; //边已经存在q->nextarc=p;}G.arcnum++;return OK;}//Insert_Arc7.17//为节省篇幅,本题只给出较为复杂的Delete_Vex算法.其余算法请自行写出. Status Delete_Vex(OLGraph &G,char v)//在十字链表表示的图G上删除顶点v { if((m=LocateVex(G,v))<0) return ERROR;n=G.vexnum;for(i=0;i<n;i++) //删除所有以v为头的边{if(G.xlist[i].firstin->tailvex==m) //如果待删除的边是头链上的第一个结点{q=G.xlist[i].firstin;G.xlist[i].firstin=q->hlink;free(q);G.arcnum--;}else //否则{for(p=G.xlist[i].firstin;p&&p->hlink->tailvex!=m;p=p->hlink);if(p){q=p->hlink;p->hlink=q->hlink;free(q);G.arcnum--;}}//else}//forfor(i=0;i<n;i++) //删除所有以v为尾的边{if(G.xlist[i].firstout->headvex==m) //如果待删除的边是尾链上的第一个结点{q=G.xlist[i].firstout;G.xlist[i].firstout=q->tlink;free(q);G.arcnum--;}else //否则{for(p=G.xlist[i].firstout;p&&p->tlink->headvex!=m;p=p->tlink);if(p){q=p->tlink;p->tlink=q->tlink;free(q);G.arcnum--;}}//else}//forfor(i=m;i<n;i++) //顺次用结点m之后的顶点取代前一个顶点{G.xlist[i]=G.xlist[i+1]; //修改表头向量for(p=G.xlist[i].firstin;p;p=p->hlink)p->headvex--;for(p=G.xlist[i].firstout;p;p=p->tlink)p->tailvex--; //修改各链中的顶点序号}G.vexnum--;return OK;}//Delete_Vex7.18//为节省篇幅,本题只给出Delete_Arc算法.其余算法请自行写出.Status Delete_Arc(AMLGraph &G,char v,char w)////在邻接多重表表示的图G上删除边(v,w){if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;if(G.adjmulist[i].firstedge->jvex==j)G.adjmulist[i].firstedge=G.adjmulist[i].firstedge->ilink;else{for(p=G.adjmulist[i].firstedge;p&&p->ilink->jvex!=j;p=p->ilink);if (!p) return ERROR; //未找到p->ilink=p->ilink->ilink;} //在i链表中删除该边if(G.adjmulist[j].firstedge->ivex==i)G.adjmulist[j].firstedge=G.adjmulist[j].firstedge->jlink;else{for(p=G.adjmulist[j].firstedge;p&&p->jlink->ivex!=i;p=p->jlink);if (!p) return ERROR; //未找到q=p->jlink;p->jlink=q->jlink;free(q);} //在i链表中删除该边G.arcnum--;return OK;}//Delete_Arc7.19Status Build_AdjMulist(AMLGraph &G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接多重表{InitAMLGraph(G);scanf("%d",&v);if(v<0) return ERROR; //顶点数不能为负G.vexnum=v;scanf(%d",&a);if(a<0) return ERROR; //边数不能为负G.arcnum=a;for(m=0;m<v;m++)G.adjmulist[m].data=getchar(); //输入各顶点的符号for(m=1;m<=a;m++){t=getchar();h=getchar(); //t为弧尾,h为弧头if((i=LocateVex(G,t))<0) return ERROR;if((j=LocateVex(G,h))<0) return ERROR; //顶点未找到p=(EBox*)malloc(sizeof(EBox));p->ivex=i;p->jvex=j;p->ilink=NULL;p->jlink=NULL; //边结点赋初值if(!G.adjmulist[i].firstedge) G.adjmulist[i].firstedge=p;else{q=G.adjmulist[i].firstedge;while(q){r=q;if(q->ivex==i) q=q->ilink;else q=q->jlink;}if(r->ivex==i) r->ilink=p;//注意i值既可能出现在边结点的ivex域中, else r->jlink=p; //又可能出现在边结点的jvex域中}//else //插入i链表尾部if(!G.adjmulist[j].firstedge) G.adjmulist[j].firstedge=p;else{q=G.adjmulist[i].firstedge;while(q){r=q;if(q->jvex==j) q=q->jlink;else q=q->ilnk;}if(r->jvex==j) r->jlink=p;else r->ilink=p;}//else //插入j链表尾部}//forreturn OK;}//Build_AdjList7.20int Pass_MGraph(MGraph G)//判断一个邻接矩阵存储的有向图是不是可传递的,是则返回1,否则返回0{for(x=0;x<G.vexnum;x++)for(y=0;y<G.vexnum;y++)if(G.arcs[x][y]){for(z=0;z<G.vexnum;z++)if(z!=x&&G.arcs[y][z]&&!G.arcs[x][z]) return 0;//图不可传递的条件}//ifreturn 1;}//Pass_MGraph分析:本算法的时间复杂度大概是O(n^2*d).7.21int Pass_ALGraph(ALGraph G)//判断一个邻接表存储的有向图是不是可传递的,是则返回1,否则返回0{for(x=0;x<G.vexnum;x++)for(p=G.vertices[x].firstarc;p;p=p->nextarc){y=p->adjvex;for(q=G.vertices[y].firstarc;q;q=q->nextarc){z=q->adjvex;if(z!=x&&!is_adj(G,x,z)) return 0;}//for}//for}//Pass_ALGraphint is_adj(ALGraph G,int m,int n)//判断有向图G中是否存在边(m,n),是则返回1,否则返回0{for(p=G.vertices[m].firstarc;p;p=p->nextarc)if(p->adjvex==n) return 1;return 0;}//is_adj7.22int visited[MAXSIZE]; //指示顶点是否在当前路径上int exist_path_DFS(ALGraph G,int i,int j)//深度优先判断有向图G中顶点i到顶点j是否有路径,是则返回1,否则返回0{if(i==j) return 1; //i就是jelse{visited[i]=1;for(p=G.vertices[i].firstarc;p;p=p->nextarc){k=p->adjvex;if(!visited[k]&&exist_path(k,j)) return 1;//i下游的顶点到j有路径}//for}//else}//exist_path_DFS7.23int exist_path_BFS(ALGraph G,int i,int j)//广度优先判断有向图G中顶点i到顶点j是否有是则返回1,否则返回0 路径,{int visited[MAXSIZE];InitQueue(Q);EnQueue(Q,i);while(!QueueEmpty(Q)){DeQueue(Q,u);visited[u]=1;for(p=G.vertices[i].firstarc;p;p=p->nextarc){k=p->adjvex;if(k==j) return 1;if(!visited[k]) EnQueue(Q,k);}//for}//whilereturn 0;}//exist_path_BFS7.24void STraverse_Nonrecursive(Graph G)//非递归遍历强连通图G { int visited[MAXSIZE];InitStack(S);Push(S,GetVex(S,1)); //将第一个顶点入栈visit(1);visited =1;while(!StackEmpty(S)){while(Gettop(S,i)&&i){j=FirstAdjVex(G,i);if(j&&!visited[j]){visit(j);visited[j]=1;Push(S,j); //向左走到尽头}}//whileif(!StackEmpty(S)){Pop(S,j);Gettop(S,i);k=NextAdjVex(G,i,j); //向右走一步if(k&&!visited[k]){visit(k);visited[k]=1;Push(S,k);}}//if}//while}//Straverse_Nonrecursive 分析:本算法的基本思想与二叉树的先序遍历非递归算法相同,请参考6.37.由于是强连通图,所以从第一个结点出发一定能够访问到所有结点. 7.25见书后解答.7.26Status TopoNo(ALGraph G)//按照题目要求顺序重排有向图中的顶点 { int new[MAXSIZE],indegree[MAXSIZE]; //储存结点的新序号n=G.vexnum;FindInDegree(G,indegree);InitStack(S);for(i=1;i<G.vexnum;i++)if(!indegree[i]) Push(S,i); //零入度结点入栈count=0;while(!StackEmpty(S)){Pop(S,i);new[i]=n--; //记录结点的拓扑逆序序号count++;for(p=G.vertices[i].firstarc;p;p=p->nextarc){k=p->adjvex;if(!(--indegree[k])) Push(S,k);}//for}//whileif(count<G.vexnum) return ERROR; //图中存在环for(i=1;i<=n;i++) printf("Old No:%d New No:%d\n",i,new[i])return OK;}//TopoNo分析:只要按拓扑逆序对顶点编号,就可以使邻接矩阵成为下三角矩阵. 7.27 int visited[MAXSIZE];int exist_path_len(ALGraph G,int i,int j,int k)//判断邻接表方式存储的有向图G的顶点i到j是否存在长度为k的简单路径{if(i==j&&k==0) return 1; //找到了一条路径,且长度符合要求else if(k>0){visited[i]=1;for(p=G.vertices[i].firstarc;p;p=p->nextarc){l=p->adjvex;if(!visited[l])if(exist_path_len(G,l,j,k-1)) return 1; //剩余路径长度减一}//forvisited[i]=0; //本题允许曾经被访问过的结点出现在另一条路径中}//elsereturn 0; //没找到}//exist_path_len7.28int path[MAXSIZE],visited[MAXSIZE]; //暂存遍历过程中的路径 intFind_All_Path(ALGraph G,int u,int v,int k)//求有向图G中顶点u到v之间的所有简单路径,k表示当前路径长度{path[k]=u; //加入当前路径中visited[u]=1;if(u==v) //找到了一条简单路径{printf("Found one path!\n");for(i=0;path[i];i++) printf("%d",path[i]); //打印输出}elsefor(p=G.vertices[u].firstarc;p;p=p->nextarc){l=p->adjvex;if(!visited[l]) Find_All_Path(G,l,v,k+1); //继续寻找}visited[u]=0;path[k]=0; //回溯}//Find_All_Pathmain(){...Find_All_Path(G,u,v,0); //在主函数中初次调用,k值应为0...}//main7.29int GetPathNum_Len(ALGraph G,int i,int j,int len)//求邻接表方式存储的有向图G的顶点i到j之间长度为len的简单路径条数{if(i==j&&len==0) return 1; //找到了一条路径,且长度符合要求else if(len>0){sum=0; //sum表示通过本结点的路径数visited[i]=1;for(p=G.vertices[i].firstarc;p;p=p->nextarc){l=p->adjvex;if(!visited[l])sum+=GetPathNum_Len(G,l,j,len-1)//剩余路径长度减一}//forvisited[i]=0; //本题允许曾经被访问过的结点出现在另一条路径中}//elsereturn sum;}//GetPathNum_Len7.30int visited[MAXSIZE];int path[MAXSIZE]; //暂存当前路径int cycles[MAXSIZE][MAXSIZE]; //储存发现的回路所包含的结点 int thiscycle[MAXSIZE]; //储存当前发现的一个回路 int cycount=0; //已发现的回路个数void GetAllCycle(ALGraph G)//求有向图中所有的简单回路 {for(v=0;v<G.vexnum;v++) visited[v]=0;for(v=0;v<G.vexnum;v++)if(!visited[v]) DFS(G,v,0); //深度优先遍历}//DFSTraversevoid DFS(ALGraph G,int v,int k)//k表示当前结点在路径上的序号 {visited[v]=1;path[k]=v; //记录当前路径for(p=G.vertices[v].firstarc;p;p=p->nextarc){w=p->adjvex;if(!visited[w]) DFS(G,w,k+1);else //发现了一条回路{for(i=0;path[i]!=w;i++); //找到回路的起点for(j=0;path[i+j];i++) thiscycle[j]=path[i+j];//把回路复制下来if(!exist_cycle()) cycles[cycount++]=thiscycle;//如果该回路尚未被记录过,就添加到记录中for(i=0;i<G.vexnum;i++) thiscycle[i]=0; //清空目前回路数组}//else}//forpath[k]=0;visited[k]=0; //注意只有当前路径上的结点visited为真.因此一旦遍历中发现当前结点visited为真,即表示发现了一条回路}//DFSint exist_cycle()//判断thiscycle数组中记录的回路在cycles的记录中是否已经存在 {int temp[MAXSIZE];for(i=0;i<cycount;i++) //判断已有的回路与thiscycle是否相同{ //也就是,所有结点和它们的顺序都相同j=0;c=thiscycle&#0;; //例如,142857和857142是相同的回路for(k=0;cycles[i][k]!=c&&cycles[i][k]!=0;k++);//在cycles的一个行向量中寻找等于thiscycle第一个结点的元素if(cycles[i][k]) //有与之相同的一个元素{for(m=0;cycles[i][k+m];m++)temp[m]=cycles[i][k+m];for(n=0;n<k;n++,m++)temp[m]=cycles[i][n]; //调整cycles中的当前记录的循环相位并放入temp 数组中if(!StrCompare(temp,thiscycle)) //与thiscycle比较return 1; //完全相等for(m=0;m<G.vexnum;m++) temp[m]=0; //清空这个数组}}//forreturn 0; //所有现存回路都不与thiscycle完全相等}//exist_cycle分析:这个算法的思想是,在遍历中暂存当前路径,当遇到一个结点已经在路径之中时就表明存在一条回路;扫描路径向量path可以获得这条回路上的所有结点.把结点序列(例如,142857)存入thiscycle中;由于这种算法中,一条回路会被发现好几次,所以必须先判断该回路是否已经在cycles中被记录过,如果没有才能存入cycles的一个行向量中.把cycles的每一个行向量取出来与之比较.由于一条回路可能有多种存储顺序,比如142857等同于285714和571428,所以还要调整行向量的次序,并存入temp数组,例如,thiscycle为142857第一个结点为1,cycles的当前向量为857142,则找到后者中的1,把1后部分提到1前部分前面,最终在temp中得到142857,与thiscycle比较,发现相同,因此142857和857142是同一条回路,不予存储.这个算法太复杂,很难保证细节的准确性,大家理解思路便可.希望有人给出更加简捷的算法.7.31int visited[MAXSIZE];int finished[MAXSIZE];int count; //count在第一次深度优先遍历中用于指示finished数组的填充位置 void Get_SGraph(OLGraph G)//求十字链表结构储存的有向图G的强连通分量 {count=0;for(v=0;v<G.vexnum;v++) visited[v]=0;for(v=0;v<G.vexnum;v++) //第一次深度优先遍历建立finished数组if(!visited[v]) DFS1(G,v);for(v=0;v<G.vexnum;v++) visited[v]=0; //清空visited数组for(i=G.vexnum-1;i>=0;i--) //第二次逆向的深度优先遍历{v=finished(i);if(!visited[v]){printf("\n"); //不同的强连通分量在不同的行输出DFS2(G,v);}}//for}//Get_SGraphvoid DFS1(OLGraph G,int v)//第一次深度优先遍历的算法{visited[v]=1;for(p=G.xlist[v].firstout;p;p=p->tlink){w=p->headvex;if(!visited[w]) DFS1(G,w);}//forfinished[++count]=v; //在第一次遍历中建立finished数组}//DFS1void DFS2(OLGraph G,int v)//第二次逆向的深度优先遍历的算法 {visited[v]=1;printf("%d",v); //在第二次遍历中输出结点序号for(p=G.xlist[v].firstin;p;p=p->hlink){w=p->tailvex;if(!visited[w]) DFS2(G,w);}//for}//DFS2分析:求有向图的强连通分量的算法的时间复杂度和深度优先遍历相同,也为O(n+e). 7.32void Forest_Prim(ALGraph G,int k,CSTree &T)//从顶点k出发,构造邻接表结构的有向图G的最小生成森林T,用孩子兄弟链表存储{for(j=0;j<G.vexnum;j++) //以下在Prim算法基础上稍作改动if(j!=k){closedge[j]={k,Max_int};for(p=G.vertices[j].firstarc;p;p=p->nextarc)if(p->adjvex==k) closedge[j].lowcost=p->cost;}//ifclosedge[k].lowcost=0;for(i=1;i<G.vexnum;i++){k=minimum(closedge);if(closedge[k].lowcost<Max_int){Addto_Forest(T,closedge[k].adjvex,k); //把这条边加入生成森林中closedge[k].lowcost=0;for(p=G.vertices[k].firstarc;p;p=p->nextarc)if(p->cost<closedge[p->adjvex].lowcost)closedge[p->adjvex]={k,p->cost};}//ifelse Forest_Prim(G,k); //对另外一个连通分量执行算法}//for}//Forest_Primvoid Addto_Forest(CSTree &T,int i,int j)//把边(i,j)添加到孩子兄弟链表表示的树T中 {p=Locate(T,i); //找到结点i对应的指针p,过程略q=(CSTNode*)malloc(sizeof(CSTNode));q->data=j;if(!p) //起始顶点不属于森林中已有的任何一棵树{p=(CSTNode*)malloc(sizeof(CSTNode));p->data=i;for(r=T;r->nextsib;r=r->nextsib);r->nextsib=p;p->firstchild=q;} //作为新树插入到最右侧else if(!p->firstchild) //双亲还没有孩子p->firstchild=q; //作为双亲的第一个孩子else //双亲已经有了孩子{for(r=p->firstchild;r->nextsib;r=r->nextsib);r->nextsib=q; //作为双亲最后一个孩子的兄弟}}//Addto_Forestmain(){...T=(CSTNode*)malloc(sizeof(CSTNode)); //建立树根T->data=1;Forest_Prim(G,1,T);...}//main分析:这个算法是在Prim算法的基础上添加了非连通图支持和孩子兄弟链表构建模块而得到的,其时间复杂度为O(n^2).7.33typedef struct {int vex; //结点序号int ecno; //结点所属的连通分量号} VexInfo; VexInfo vexs[MAXSIZE]; //记录结点所属连通分量号的数组void Init_VexInfo(VexInfo &vexs[ ],int vexnum)//初始化 { for(i=0;i<vexnum;i++)vexs[i]={i,i}; //初始状态:每一个结点都属于不同的连通分量 }//Init_VexInfoint is_ec(VexInfo vexs[ ],int i,int j)//判断顶点i和顶点j是否属于同一个连通分量{if(vexs[i].ecno==vexs[j].ecno) return 1;else return 0;}//is_ecvoid merge_ec(VexInfo &vexs[ ],int ec1,int ec2)//合并连通分量ec1和ec2{for(i=0;vexs[i].vex;i++)if(vexs[i].ecno==ec2) vexs[i].ecno==ec1;}//merge_ecvoid MinSpanTree_Kruscal(Graph G,EdgeSetType &EdgeSet,CSTree &T)//求图的最小生成树的克鲁斯卡尔算法{Init_VexInfo(vexs,G.vexnum);ecnum=G.vexnum; //连通分量个数while(ecnum>1){GetMinEdge(EdgeSet,u,v); //选出最短边if(!is_ec(vexs,u,v)) //u和v属于不同连通分量{Addto_CSTree(T,u,v); //加入到生成树中merge_ec(vexs,vexs[u].ecno,vexs[v].ecno); //合并连通分量ecnum--;}DelMinEdge(EdgeSet,u,v); //从边集中删除}//while}//MinSpanTree_Kruscalvoid Addto_CSTree(CSTree &T,int i,int j)//把边(i,j)添加到孩子兄弟链表表示的树T中 {p=Locate(T,i); //找到结点i对应的指针p,过程略q=(CSTNode*)malloc(sizeof(CSTNode));q->data=j;if(!p->firstchild) //双亲还没有孩子p->firstchild=q; //作为双亲的第一个孩子else //双亲已经有了孩子{for(r=p->firstchild;r->nextsib;r=r->nextsib);r->nextsib=q; //作为双亲最后一个孩子的兄弟}}//Addto_CSTree分析:本算法使用一维结构体变量数组来表示等价类,每个连通分量所包含的所有结点属于一个等价类.在这个结构上实现了初始化,判断元素是否等价(两个结点是否属于同一个连通分量),合并等价类(连通分量)的操作.7.34Status TopoSeq(ALGraph G,int new[ ])//按照题目要求给有向无环图的结点重新编号,并存入数组new中{int indegree[MAXSIZE]; //本算法就是拓扑排序FindIndegree(G,indegree);Initstack(S);for(i=0;i<G.vexnum;i++)if(!indegree[i]) Push(S,i);count=0;while(!stackempty(S)){Pop(S,i);new[i]=++count; //把拓扑顺序存入数组的对应分量中for(p=G.vertices[i].firstarc;p;p=p->nextarc){k=p->adjvex;if(!(--indegree[k])) Push(S,k);}}//whileif(count<G.vexnum) return ERROR;return OK;}//TopoSeq7.35int visited[MAXSIZE];void Get_Root(ALGraph G)//求有向无环图的根,如果有的话{for(v=0;v<G.vexnum;v++){for(w=0;w<G.vexnum;w++) visited[w]=0;//每次都要将访问数组清零DFS(G,v); //从顶点v出发进行深度优先遍历for(flag=1,w=0;w<G.vexnum;w++)if(!visited[w]) flag=0; //如果v是根,则深度优先遍历可以访问到所有结点if(flag) printf("Found a root vertex:%d\n",v);}//for}//Get_Root,这个算法要求图中不能有环,否则会发生误判void DFS(ALGraph G,int v){visited[v]=1;for(p=G.vertices[v].firstarc;p;p=p->nextarc){w=p->adjvex;if(!visited[w]) DFS(G,w);}}//DFS7.36void Fill_MPL(ALGraph &G)//为有向无环图G添加MPL域 {FindIndegree(G,indegree);for(i=0;i<G.vexnum;i++)if(!indegree[i]) Get_MPL(G,i);//从每一个零入度顶点出发构建MPL域 }//Fill_MPLint Get_MPL(ALGraph &G,int i)//从一个顶点出发构建MPL域并返回其MPL 值 {if(!G.vertices[i].firstarc){G.vertices[i].MPL=0;return 0; //零出度顶点}else{max=0;for(p=G.vertices[i].firstarc;p;p=p->nextarc){j=p->adjvex;if(G.vertices[j].MPL==0) k=Get_MPL(G,j);if(k>max) max=k; //求其直接后继顶点MPL的最大者}G.vertices[i]=max+1;//再加一,就是当前顶点的MPLreturn max+1;}//else}//Get_MPL7.37int maxlen,path[MAXSIZE]; //数组path用于存储当前路径 intmlp[MAXSIZE]; //数组mlp用于存储已发现的最长路径 voidGet_Longest_Path(ALGraph G)//求一个有向无环图中最长的路径 { maxlen=0;FindIndegree(G,indegree);for(i=0;i<G.vexnum;i++){for(j=0;j<G.vexnum;j++) visited[j]=0;if(!indegree[i]) DFS(G,i,0);//从每一个零入度结点开始深度优先遍历}printf("Longest Path:");for(i=0;mlp[i];i++) printf("%d",mlp[i]); //输出最长路径 }//Get_Longest_Pathvoid DFS(ALGraph G,int i,int len) {visited[i]=1;path[len]=i;if(len>maxlen&&!G.vertices[i].firstarc) //新的最长路径{for(j=0;j<=len;j++) mlp[j]=path[j]; //保存下来maxlen=len;}else{for(p=G.vertices[i].firstarc;p;p=p->nextarc){j=p->adjvex;if(!visited[j]) DFS(G,j,len+1);}}//elsepath[i]=0;visited[i]=0;}//DFS7.38void NiBoLan_DAG(ALGraph G)//输出有向无环图形式表示的表达式的逆波兰式 {FindIndegree(G,indegree);for(i=0;i<G.vexnum;i++)if(!indegree[i]) r=i; //找到有向无环图的根PrintNiBoLan_DAG(G,i);}//NiBoLan_DAGvoid PrintNiBoLan_DAG(ALGraph G,int i)//打印输出以顶点i为根的表达式的逆波兰式 {c=G.vertices[i].data;if(!G.vertices[i].firstarc) //c是原子printf("%c",c);else //子表达式{p=G.vertices[i].firstarc;PrintNiBoLan_DAG(G,p->adjvex);PrintNiBoLan_DAG(G,p->nexarc->adjvex);printf("%c",c);}}//PrintNiBoLan_DAG7.39void PrintNiBoLan_Bitree(Bitree T)//在二叉链表存储结构上重做上一题 { if(T->lchild) PrintNiBoLan_Bitree(T->lchild);if(T->rchild) PrintNiBoLan_Bitree(T->rchild);printf("%c",T->data);}//PrintNiBoLan_Bitree7.40int Evaluate_DAG(ALGraph G)//给有向无环图表示的表达式求值 { FindIndegree(G,indegree);for(i=0;i<G.vexnum;i++)if(!indegree[i]) r=i; //找到有向无环图的根return Evaluate_imp(G,i); }//NiBoLan_DAGint Evaluate_imp(ALGraph G,int i)//求子表达式的值{if(G.vertices[i].tag=NUM) return G.vertices[i].value;else{p=G.vertices[i].firstarc;v1=Evaluate_imp(G,p->adjvex);v2=Evaluate_imp(G,p->nextarc->adjvex);return calculate(v1,G.vertices[i].optr,v2);}}//Evaluate_imp分析:本题中,邻接表的vertices向量的元素类型修改如下: struct { enum tag{NUM,OPTR};union {int value;char optr;};ArcNode * firstarc;} Elemtype;7.41void Critical_Path(ALGraph G)//利用深度优先遍历求网的关键路径 { FindIndegree(G,indegree);for(i=0;i<G.vexnum;i++)if(!indegree[i]) DFS1(G,i); //第一次深度优先遍历:建立vefor(i=0;i<G.vexnum;i++)if(!indegree[i]) DFS2(G,i); //第二次深度优先遍历:建立vlfor(i=0;i<=G.vexnum;i++)if(vl[i]==ve[i]) printf("%d",i); //打印输出关键路径}//Critical_Pathvoid DFS1(ALGraph G,int i) {if(!indegree[i]) ve[i]=0;for(p=G.vertices[i].firstarc;p;p=p->nextarc) {dut=*p->info;if(ve[i]+dut>ve[p->adjvex])ve[p->adjvex]=ve[i]+dut;DFS1(G,p->adjvex);}}//DFS1void DFS2(ALGraph G,int i) {if(!G.vertices[i].firstarc) vl[i]=ve[i]; else{for(p=G.vertices[i].firstarc;p;p=p->nextarc) {DFS2(G,p->adjvex);dut=*p->info;if(vl[p->adjvex]-dut<vl[i])vl[i]=vl[p->adjvex]-dut;}}//else}//DFS27.42void ALGraph_DIJ(ALGraph G,int v0,Pathmatrix &P,ShortestPathTable &D)//在邻接表存储结构上实现迪杰斯特拉算法{for(v=0;v<G.vexnum;v++)D[v]=INFINITY;for(p=G.vertices[v0].firstarc;p;p=p->nextarc)D[p->adjvex]=*p->info; //给D数组赋初值for(v=0;v<G.vexnum;v++){final[v]=0;for(w=0;w<G.vexnum;w++) P[v][w]=0; //设空路径if(D[v]<INFINITY){P[v][v0]=1;P[v][v]=1;}}//forD[v0]=0;final[v0]=1; //初始化for(i=1;i<G.vexnum;i++){min=INFINITY;for(w=0;w<G.vexnum;w++)if(!final[w])if(D[w]<min) //尚未求出到该顶点的最短路径{v=w;min=D[w];}final[v]=1;for(p=G.vertices[v].firstarc;p;p=p->nextarc){w=p->adjvex;if(!final[w]&&(min+(*p->info)<D[w])) //符合迪杰斯特拉条件{D[w]=min+edgelen(G,v,w);P[w]=P[v];P[w][w]=1; //构造最短路径}}//for}//for}//ALGraph_DIJ分析:本算法对迪杰斯特拉算法中直接取任意边长度的语句作了修改.由于在原算法中,每次循环都是对尾相同的边进行处理,所以可以用遍历邻接表中的一条链来代替.。

数据结构[严蔚敏]7

数据结构[严蔚敏]7
边,这样的无向图称为完全无向图。
完全有向图:对于有向图,若图中顶点数为n ,用
e表示弧的数目,则e[0,n(n-1)] 。具有n(n-1)条边的有 向图称为完全有向图。
完全有向图另外的定义是:
对于有向图G=(V,E),若vi,vjV ,当vi ≠vj时,有 <vi ,vj>E∧<vj , vi >E ,即图中任意两个不同的顶点间都有一 条弧,这样的有向图称为完全有向图。 有很少边或弧的图(e<n㏒n)的图称为稀疏图,反之称为 稠密图。
连通图、图的连通分量:对无向图G=(V,E),若vi ,
vj V,vi和vj都是连通的,则称图G是连通图,否则称为非连 通图。若G是非连通图,则极大的连通子图称为G的连通分 量。 对有向图G=(V,E),若vi ,vj V,都有以vi为起点, vj 为终点以及以vj为起点,vi为终点的有向路径,称图G是强连 通图,否则称为非强连通图。若G是非强连通图,则极大的 强连通子图称为G的强连通分量。 “极大”的含义:指的是对子图再增加图G中的其它顶 点,子图就不再连通。
a c b e d c b e a d a
6 3
b
3
2
c
4
d
1
5
e
(a) 有向图
(b) 生成森林
图7-3 有向图及其生成森林
图7-4 带权有向图
7.1.2 图的抽象数据类型定义
图是一种数据结构,加上一组基本操作就构成了图 的抽象数据类型。 图的抽象数据类型定义如下: ADT Graph{
数据对象V:具有相同特性的数据元素的集合,称为 顶点集。
(c) 邻接矩阵
图7-8 带权有向图的数组存储
⑶ 有向图邻接矩阵的特性

数据结构-严蔚敏共72页文档

数据结构-严蔚敏共72页文档

37、我们唯一不会改正的缺点是软弱。——拉罗什福不后退。——亚伯拉罕·林肯
39、勿问成功的秘诀为何,且尽全力做你应该做的事吧。——美华纳
40、学而不思则罔,思而不学则殆。——孔子
45、法律的制定是为了保证每一个人 自由发 挥自己 的才能 ,而不 是为了 束缚他 的才能 。—— 罗伯斯 庇尔
谢谢!
36、自己的鞋子,自己知道紧在哪里。——西班牙
数据结构-严蔚敏
41、实际上,我们想要的不是针对犯 罪的法 律,而 是针对 疯狂的 法律。 ——马 克·吐温 42、法律的力量应当跟随着公民,就 像影子 跟随着 身体一 样。— —贝卡 利亚 43、法律和制度必须跟上人类思想进 步。— —杰弗 逊 44、人类受制于法律,法律受制于情 理。— —托·富 勒

chap007 图-数据结构(C语言版)-严蔚敏-清华大学出版社

chap007 图-数据结构(C语言版)-严蔚敏-清华大学出版社

路径上边的数目称作路径长度。
如:长度为3的路径 简单路径:序列中顶点
{A,B,C,F}
不重复出现的路径。
A
简单回路:序列中第一
B
E 个顶点和最后一个顶
CF
点相同的路径。
若图G中任意两个顶
B
点之间都有路径相通,
则称此图为连通图; A
C D
B A
F
C
F
E
D E
若无向图为非连通图, 则图中各个极大连通 子图称作此图的连通 分量。
7.2 图的存储表示
一、图的数组(邻接矩阵)存储表示 二、图的邻接表存储表示 三、有向图的十字链表存储表示 四、无向图的邻接多重表存储表示
一、图的数组(邻接矩阵)存储表示
{ 定义:矩阵的元素为 0 (i,j)VR Aij= 1 (i,j)VR
B A
F
C D
E
010010 100010 000101 001001 110000 011100
对有向图,若任意两个顶点之间都存在
一条有向路径,则称此有向图为强连通图。
否则,其各个强连通子图称作它的 强连通分量。
A
A
B
EB
E
CF
CF
假设一个连通图有 n 个顶点和 e 条边, 其中 n-1 条边和 n 个顶点构成一个极小连 通子图,称该极小连通子图为此连通图的 生成树。
B A
F
C D
E
对非连通图,则 称由各个连通分 量的生成树的集 合为此非连通图 的生成森林。
基本操作
结构的建立和销毁 对顶点的访问操作
插入或删除顶点 插入和删除弧
对邻接点的操作 遍历
结构的建立和销毁CreFra bibliotektGraph(&G, V, VR): // 按定义(V, VR) 构造图
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例如:
数 据 结 构
B A
F
C
D E
其中 V2={A,B,C,D,E,F} E2={(A,B),(A,E),(B,E),(C,D), (D,F),(B,F),(C,F)}
4
第7章 图
7.1 图的定义与相关术语
名词和基本术语 假设图中有 n 个顶点,e 条边,则
数 据 结 构
含 e=n(n-1)/2 条边的无向图称作完全图; 含 e=n(n-1) 条弧的有向图称作有向完全图; 若边或弧的个数 e<nlogn,则称作稀疏图, 否则称作稠密图。
22
第7章 图
7.2图的存储结构
②图的邻接表表示法 (链式存储法)
数 据 结 构
有向图 A B C D E
1 2 3 4 5
A B C D E
2 3∧ 4∧ 1 3∧
5∧
2∧
23
第7章 图
7.2图的存储结构
②图的邻接表表示法 (链式存储法)
数 据 结 构
有向网
15
A
11
7 21
9
B
3
E
1 2 3 4 5
7.3 图的遍历
①深度优先搜索算法思想: 递归
数 据 结 构
Ⅰ.访问出发点v0 ;
Ⅱ.依次以v0的未被访问的邻接点为出发点, 深度优先搜索图,直至图中所有与v0有 路径相通的顶点都被访问。 对于非连通图,则图中一定还有顶点未被访 问,要从图中另选一个未被访问的顶点作为 起始点,重复上述深度优先搜索过程。
5
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
若无向图顶点v 和w 之间存在一条边(v,w),则 称顶点v 和w 互为邻接点,称边(v,w)依附于顶 点v 和w 或边(v,w)与顶点v 和w相关联。 与顶点v 关联的边的数目定义为v的度(ID)。
例如: A F E
6
B
C ID(B) = 3
j=1
n
Ⅱ.便于运算 有向图(网):
OD(vi)= ∑A[ i,j ]
j=1
n
ID(vi)= ∑A[ j,i ]
j=1
20
n
第7章 图
7.2图的存储结构
②图的邻接表表示法 (链式存储法)
数 据 结 构
对图中每个顶点建立一个单链表,第i个 单链表中的结点表示依附于顶点vi的边。 Ⅰ.表头结点 data first
B
C D
E
18
第7章 图
7.2图的存储结构
①图的邻接矩阵表示法 (数组表示法)
一维数组:用于存储顶点信息。
数 据 结 构
二维数组: 用于存储图中顶点之间关联关系
邻接矩阵
A[i,j]=
有向网
15
1 ij 若<vi,vj>或(vi,vj)VR w
0 反之 ∞
A B C D E
A
11 7 21
9
B
3
E D
ID(vi)扫描整个邻接表
逆邻接表
25
第7章 图
7.2图的存储结构
逆邻接表 ②图的邻接表表示法 (链式存储法)
数 据 结 构
有向图 A B C D E
1 2 3 4 5
A B C D E
4∧ 1 2 3∧ 1∧
4∧ 5∧
26
第7章 图
7.2图的存储结构
③有向图的十字链表表示法(链式存储法)
数 据 结 构
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
对非连通图,则称由各个连通分量的生成树 的集合为此非连通图的生成森林。
B A C
D F E
14
第7章 图
7.1 图的定义与相关术语
有向图或无向图中的弧或边带权 后的图分别称作有向网或无向网。
15
数 据 结 构
A
11 7 21
9
B
3
E
D
C 2
15
C 2
A BCD E ∞ 15 ∞ ∞ 9 ∞∞ 3 ∞∞ ∞∞ ∞ 2 ∞ 11 7 ∞ ∞ ∞ ∞ ∞ 21 ∞ ∞
非 对 称 矩 阵
19
第7章 图
7.2图的存储结构
特点: ①图的邻接矩阵表示法 (数组表示法)
数 据 结 构
Ⅰ.存储空间
n(n-1)/2 无向图: n 有向图(网): 2 无向图: TD(vi)= ∑A[ i,j ]
A B C D E
2 3 4 1 3
15 5 9 ∧ 3 ∧ 2 ∧ 11 2 7 ∧ 21 ∧
C 2
D
24
第7章 图
7.2图的存储结构
特点: ②图的邻接表表示法 (链式存储法)
数 据 结 构
n+2e Ⅰ.无向图存储空间: 无向图: TD(vi)= 第i个单链表上结点的个数 Ⅱ. 有向图(网): OD(vi)=第i个单链表上结点的个数
其中: V={|v∈DataObject} R={E} E={<v,w>| P(v,w)且(v,w∈V)} <v,w>表示从 v 到 w 的一条弧,并称 v 为弧尾,w 为弧头。
谓词 P(v,w) 定义了弧 <v,w>的意义或信息, 表示从v到w的一条单向通道。
2
第7章 图
7.1 图的定义与相关术语
例如: OD(B)= 1 ID(B)= 2 TD(B)= 3
B
C D
E
7
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
设图G=(V,{VR})中的{ u=vi,0,vi,1, …, vi,m=w}顶点 序列中, 有 (vi,j-1,vi,j)VR 1≤j≤m, 则称从顶点u到 顶点w之间存在一条路径。路径上边的数目称作路 径长度,有向图的路径也是有向的。
{A,E,C,D,A}
9
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
设图G=(V,{VR}) 和图 G=(V,{VR}), 且 VV, VRVR,则称 G 为 G 的子图。
例如: A B C D E A A E C D D
B
10
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
若无向图G中任意两个顶点之间都 有路径相通,则称此图为连通图。
B A C
B D A
F
C
D E
F
E
若无向图为非连通图,则图中各个 极大连通子图称作此图的连通分量。
11
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
对有向图, 若任意两个顶点之间都存在一 条有向路径,则称此有向图为强连通图。
从图中某个顶点出发遍历图,访遍图中其余顶 点,并且使图中的每个顶点仅被访问一次的过程。
数 据 结 构
①深度优先搜索(一条道走到黑) ②广度优先搜索(水波)
31
第7章 图
7.3 图的遍历
①深度优先搜索 基本思想: Ⅰ.从图中某个顶点v0出发,首先访问v0 ;
数 据 结 构
Ⅱ.找出刚访问过的顶点的第一个未被访问的邻接点, 然后访问该顶点。以该顶点为新顶点,重复此步骤, 直到刚访问过的顶点没有未被访问的邻接点为止; Ⅲ.返回前一个访问过的且仍有未被访问的邻接点的顶 点,找出该顶点的下一个未被访问的邻接点,访问 该顶点。然后执行步骤Ⅱ。 类似于树的先根次序遍历
Ⅱ.表结点


adjvex nextarc adjvex info nextarc
21
第7章 图
7.2图的存储结构
②图的邻接表表示法 (链式存储法)
数 据 结 构
无向图 B C A F E D
1 2 3 4 5 6
A B C D E F
2 1 4 3 1 2
5 5 6 6 2 3
∧ 6 ∧ ∧ ∧ ∧ 4 ∧
A A E C D
B
B
C D
E
否则,其各强连通子图称作它的强连通分量。
12
第7章 图
7.1 图的定义与相关术语
名词和基本术语
数 据 结 构
假设一个连通图有 n 个顶点和 e 条边, 其中 n-1 条边和 n 个顶点构成一个极小连通子图, 称该极小连通子图为此连通图的生成树。
B
A F E
13
C
D
第7章 图
边的结点结构
顶点的结点结构
mark ivex ilink jvex jlink
data firstedge
29
第7章 图
无向图 A
B C E
7.2图的存储结构
④无向图的邻接多重表表示法
数 据 结 构
D
1 2 3 4 5
A B C D E
1
2
1
4∧
3
2
3
4
5
2∧
3∧ 5 ∧
30
第7章 图
7.3 图的遍历
7.2图的存储结构
③有向图的十字链表表示法
1 A
数 据 结 构
1 2 2 3
2 B 3 C 4 D 5 E 4 1∧ 4 2 ∧∧
∧ 3 4 ∧∧
5 3 ∧∧
28
第7章 图
7.2图的存储结构
④无向图的邻接多重表表示法
数 据 结 构
顶点和边分别各用一种存储结构的结点表示。依附于相同 顶点的边被链在同一链表上,每条边依附于两个顶点,所 以每个边结点同时被链接在两个链表中,链表的头结点就 是顶点结点。同时还在边结点中增加了一个访问标志位。
有向图 :由于“弧”是有方向的,因此称 由顶点集和弧集构成的图为有向图。
相关文档
最新文档