数据结构C语言版 无向图的邻接多重表存储表示和实现
数据结构 邻接多重表
数据结构邻接多重表摘要:1.邻接多重表的定义和特点2.邻接多重表的存储方式3.邻接多重表的优缺点分析4.邻接多重表的应用实例正文:一、邻接多重表的定义和特点邻接多重表(Adjacency List)是一种用于表示有向图或无向图中顶点之间关系的数据结构。
它通过一个顶点表和一组边表来表示图的顶点和边。
邻接多重表具有以下特点:1.每个顶点对应一个边表,边表中存储与该顶点相邻的所有顶点。
2.如果两个顶点之间存在一条边,则它们在各自的边表中相互出现。
3.边表中的元素为顶点序号,而非顶点本身。
二、邻接多重表的存储方式邻接多重表的存储方式包括顺序存储和链式存储两种:1.顺序存储:将所有顶点及其边表按顺序排列在一个数组中。
这种存储方式的优点是访问速度快,但需要较大的存储空间。
2.链式存储:每个顶点对应一个链表,链表中存储与该顶点相邻的所有顶点。
这种存储方式的优点是节省存储空间,但访问速度较慢。
三、邻接多重表的优缺点分析邻接多重表的优点:1.表示简单,易于理解。
2.便于实现和操作。
3.可以灵活表示有向图和无向图。
邻接多重表的缺点:1.存储空间较大,尤其是当图规模较大时。
2.链式存储的访问速度较慢,可能影响算法效率。
四、邻接多重表的应用实例邻接多重表广泛应用于图论算法中,如深度优先搜索(DFS)、广度优先搜索(BFS)、最短路径算法(如Dijkstra 算法、Floyd-Warshall 算法等)等。
这些算法通常需要使用邻接多重表来表示图的顶点和边,并进行相应的操作。
总之,邻接多重表是一种重要的数据结构,用于表示图的顶点和边。
它具有表示简单、易于实现等优点,但也存在存储空间较大、访问速度较慢等缺点。
数据结构中有向图和无向图的c语言实现
#include<iostream.h>
#include<malloc.h>
#define M 50
typedef char vextype;//顶点数据类型char
typedef struct node //定义表结点类型
{
int adjvex;//邻接点域
struct node *link;//指针域
}
cout<<"以(0,0)为输入结束符"<<endl;
cout<<"输入一条边依附的两个顶点序号:";
cin>>i>>j;
while((i>0)&&(j>0))//输入的(i,j)为(0,0)作为结束符号
{
p=(edgenode*)malloc(sizeof(edgenode));//生成邻接序号为j的表结点
break;
default:cout<<"输入错误,程序结束!"<<endl;
return;
}
cout<<endl;
cout<<"是否继续?(输入n结束,输入y有效!)"<<endl;
cin>>flag;
}
cout<<"程序结束,再见!"<<endl;
}
}edgenode,*Edgenode;
typedef struct headnode//定义表头结点类型
{
vextype vexdata;//顶点数据域
数据结构(C语言版)
比较
Prim算法适用于稠密图, Kruskal算法适用于稀疏图;
两者时间复杂度相近,但 Kruskal算法需额外处理并查
集数据结构。
最短路径算法设计思想及实现方法比较
1 2
Dijkstra算法
从源点出发,每次找到距离源点最近的顶点并更 新距离值,直至所有顶点距离确定。适用于不含 负权边的图。
Floyd算法
特殊二叉树
满二叉树、完全二叉树等。
二叉树的遍历与线索化
二叉树的遍历
前序遍历、中序遍历、后序遍历和层 次遍历是二叉树的四种基本遍历方法 。
线索化二叉树
为了方便查找二叉树节点的前驱和后 继,可以对二叉树进行线索化处理, 即在节点的空指针域中存放指向前驱 或后继的指针。
树和森林的遍历与转换
树的遍历
01
串的顺序存储结构
01
02
03
串的顺序存储结构是用 一组地址连续的存储单 元来存储串中的字符序
列的。
按照预定义的大小,为 每个定义的串变量分配 一个固定长度的存储区 ,一般是用定长数组来
定义。
串值的存储:将实际串 长度值保存在数组的0下 标位置,串的字符序列 依次存放在从1开始的数
组元素中。
串的链式存储结构
03
比较
DFS空间复杂度较低,适用于递 归实现;BFS可找到最短路径, 适用于非递归实现。
最小生成树算法设计思想及实现方法比较
Prim算法
从某一顶点开始,每次选择当 前生成树与外界最近的边加入 生成树中,直至所有顶点加入
。
Kruskal算法
按边权值从小到大排序,依次 选择边加入生成树中,保证不
形成环路。
数据结构(C语言版)
数据结构(C语言)
广义表
由一个大的表像数组中一样存储元素,但内部的元素可以使结构不一样的,或者是所谓的子广义表。(树和有向图也可以用广义表来表示)
树
树的存储结构:
1、双亲表示法(用一组连续的存储空间(一维数组)存储树中的各个结点,数组中的一个元素表示树中的一个结点,数组元素为结构体类型,其中包括结点本身的信息以及结点的双亲结点在数组中的序号,但是这样并不能反映出孩子结点之间的兄弟关系来,所以,得利用一些手法来区别兄弟,可在结点结构中增设存放第一个孩子的域和存放第一个右兄弟的域,就能较方便地实现上述操作了,在实际存储的时候,第一列是序号,第二列是数据的具体内容,第三列则是通过固定的数字关系来反映这是第几代父母,第一代也就是根结点,其为-1,一下慢慢变大。这种存储方法比较适应存储数据和查找父结点。)
队列也是一种特殊的线性表。它所有的插入操作均限定在表的一端进行,而所有的删除操作则限定在表的另一端进行。允许删除元素的一端称为队头,允许插入元素的一端称为队尾,删除元素称为出队,插入元素称为进队。(假如是一个循环队列是会出现队满和队空的情况)
队列的顺序存储结构:利用连续的存储单元存储队列。
队列的链式存储结构:利用地址对队列中的数据进行连接,但存储的数据不一定连续。
数据组织(数据、数据元素、数据项)的三个层次:数据可由若干个数据元素构成,而数据元素又可以由一个或若干个数据项组成。
四种基本的数据结构:集合、线性结构、树形结构、图状结构。
顺序存储的特点是在内存中开辟一组连续的空间来存放数据,数据元素之间的逻辑关系通过元素在内存中存放的相对位置来确定。
数据结构C语言
数据结构(C语言)数据组织(数据、数据元素、数据项)的三个层次:数据可由若干个数据元素构成,而数据元素又可以由一个或若干个数据项组成。
四种基本的数据结构:集合、线性结构、树形结构、图状结构。
顺序存储的特点是在内存中开辟一组连续的空间来存放数据,数据元素之间的逻辑关系通过元素在内存中存放的相对位置来确定。
链式存储的特点是通过指针反映数据元素之间的逻辑关系。
数据类型:原子类型、结构类型。
线性表定义:线性表是n个数据元素的有限序列。
线性表的顺序存储结构:表中相邻的元素a和b所对应的存储地址A和B 也是相邻的。
(也就是数据都是按照表中情况进行连续存储的情况)线性表的链式存储结构:该线性表中的数据元素可以用任意的存储单元来存储。
表中的各个相邻的数据(元素)是通过一个指针地址来进行链接的,以找到下一个数据(元素)在哪。
其形式一般为:数据地址线性表的顺序和链式存储结构的比较:在线性表的长度变化比较大,预先难以确定的情况下,最好采用动态链表作为存储结构。
当线性表的长度变化不大时,采用顺序存储结构比较节省存储空间。
在顺序表结构的线性表上主要进行查找、读取而很少做插入和删除的操作。
链式结构的线性表中比较适应做插入和删除的操作。
一元多项式的加减法运算可先将一元多项式进行了改变存储之后再进行运算比较适宜,将一元多项式转换为用在内存中的前一项表示阶数,后一项表示对应该阶数的系数。
然后利用这种形式进行加减运算。
栈和队列栈是限定在表的同一端进行插入或删除操作的线性表,即进栈、出栈。
(特殊的线性表)栈的顺序存储结构:利用一组地址连续的存储单元依次从栈底到栈顶存放数据元素,栈底位置固定不变,可将栈底设在向量低下标的一端。
栈的链式存储结构:用单链表作为存储结构的栈称为链栈,链表的最后一个结点表示栈底,第一个结点表示栈顶。
队列也是一种特殊的线性表。
它所有的插入操作均限定在表的一端进行,而所有的删除操作则限定在表的另一端进行。
允许删除元素的一端称为队头,允许插入元素的一端称为队尾,删除元素称为出队,插入元素称为进队。
数据结构图的存储结构及基本操作
数据结构图的存储结构及基本操作数据结构图的存储结构及基本操作1·引言数据结构图是一种用来描述数据元素之间关系的图形结构,它可以表示实体之间的联系和依赖关系。
本文将介绍数据结构图的存储结构及基本操作。
2·存储结构2·1 邻接矩阵邻接矩阵是使用二维数组来表示数据结构图中各个节点之间的关系。
矩阵的行和列代表节点,如果两个节点之间存在边,则矩阵相应位置的值为1,否则为0。
2·2 邻接表邻接表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有一个链表,链表中的每个元素表示与该节点相邻的节点。
2·3 十字链表十字链表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有两个链表,一个表示该节点指向的节点,另一个表示指向该节点的节点。
2·4 邻接多重表邻接多重表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有一个链表,链表中的每个元素表示与该节点相邻的边。
3·基本操作3·1 创建图创建一个空的数据结构图,根据需要选择适当的存储结构。
3·2 插入节点在数据结构图中插入一个节点,并建立与其他节点的关系。
3·3 删除节点从数据结构图中删除一个节点,并删除与其他节点的关系。
3·4 插入边在数据结构图中插入一条边,连接两个节点。
3·5 删除边从数据结构图中删除一条边,断开两个节点的连接。
3·6 遍历图按照某种规则遍历整个数据结构图,访问每个节点。
本文档涉及附件:无本文所涉及的法律名词及注释:1·邻接矩阵:用于表示图的存储结构,矩阵的行和列代表图的节点,矩阵的值表示节点之间的连接关系。
2·邻接表:用于表示图的存储结构,每个节点都有一个链表,链表中的每个元素表示与该节点相邻的节点。
3·十字链表:用于表示图的存储结构,每个节点都有两个链表,一个表示该节点指向的节点,另一个表示指向该节点的节点。
数据结构C语言版-无向图的邻接多重表存储表示和实现
数据结构C语言版无向图的邻接多重表存储表示和实现.txt只要你要,只要我有,你还外边转什么阿老实在我身边待着就行了。
听我的就是,问那么多干嘛,我在你身边,你还走错路!跟着我!不能给你幸福是我的错,但谁让你不幸福,我TMD去砍了他/* 数据结构C语言版无向图的邻接多重表存储表示和实现P166编译环境:Dev-C++ 4.9.9.2日期:2011年2月15日*/#include <stdio.h>#include <malloc.h>#define MAX_NAME 3 // 顶点字符串的最大长度+1#define MAX_INFO 80 // 相关信息字符串的最大长度+1typedef char InfoType;typedef char VertexType[MAX_NAME]; // 字符串类型// AMLGraph.h 无向图的邻接多重表存储表示#define MAX_VERTEX_NUM 20typedef enum{unvisited,visited}VisitIf;typedef struct EBox{VisitIf mark; // 访问标记int ivex,jvex; // 该边依附的两个顶点的位置struct EBox *ilink,*jlink; // 分别指向依附这两个顶点的下一条边InfoType *info; // 该边信息指针}EBox;typedef struct{VertexType data;EBox *firstedge; // 指向第一条依附该顶点的边}VexBox;typedef struct{VexBox adjmulist[MAX_VERTEX_NUM];int vexnum,edgenum; // 无向图的当前顶点数和边数}AMLGraph;typedef int QElemType;// 单链队列--队列的链式存储结构typedef struct QNode{QElemType data; //数据域struct QNode *next; //指针域}QNode,*QueuePtr;typedef struct{QueuePtr front,//队头指针,指针域指向队头元素rear; //队尾指针,指向队尾元素}LinkQueue;// 若G中存在顶点u,则返回该顶点在无向图中位置;否则返回-1int LocateVex(AMLGraph G,VertexType u){int i;for(i=0;i<G.vexnum;++i)if(strcmp(u,G.adjmulist[i].data)==0)return i;return -1;}// 采用邻接多重表存储结构,构造无向图Gint CreateGraph(AMLGraph *G){int i,j,k,l,IncInfo;char s[MAX_INFO];VertexType va,vb;EBox *p;printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");scanf("%d,%d,%d",&(*G).vexnum,&(*G).edgenum,&IncInfo);printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);for(i=0;i<(*G).vexnum;++i) // 构造顶点向量{scanf("%s",(*G).adjmulist[i].data);(*G).adjmulist[i].firstedge=NULL;}printf("请顺序输入每条边的两个端点(以空格作为间隔):\n");for(k=0;k<(*G).edgenum;++k) // 构造表结点链表{scanf("%s%s%*c",va,vb); // %*c吃掉回车符i=LocateVex(*G,va); // 一端j=LocateVex(*G,vb); // 另一端p=(EBox*)malloc(sizeof(EBox));p->mark=unvisited; // 设初值p->ivex=i;p->jvex=j;p->info=NULL;p->ilink=(*G).adjmulist[i].firstedge; // 插在表头(*G).adjmulist[i].firstedge=p;p->jlink=(*G).adjmulist[j].firstedge; // 插在表头(*G).adjmulist[j].firstedge=p;if(IncInfo) // 边有相关信息{printf("请输入该弧的相关信息(<%d个字符):",MAX_INFO);gets(s);l=strlen(s);if(l){p->info=(char*)malloc((l+1)*sizeof(char));strcpy(p->info,s);}}}return 1;}// 返回v的值VertexType* GetVex(AMLGraph G,int v){if(v>=G.vexnum||v<0)exit(0);return &G.adjmulist[v].data;}// 对v赋新值valueint PutVex(AMLGraph *G,VertexType v,VertexType value){int i;i=LocateVex(*G,v);if(i<0) // v不是G的顶点return 0;strcpy((*G).adjmulist[i].data,value);return 1;}// 返回v的第一个邻接顶点的序号。
数据结构(C语言版本)
2018/10/9
华侨大学数学系 黄建新
1.1 引言
• 众所周知,二十世纪四十年代,电子数字计算机问世的直接原因是解
决弹道学的计算问题。早期,电子计算机的应用范围,几乎只局限于 科学和工程的计算,其处理的对象是纯数值性的信息,通常,人们把 这类问题称为数值计算。 • 近三十年来,电子计算机的发展异常迅猛,这不仅表现在计算机本身 运算速度不断提高、信息存储量日益扩大、价格逐步下降,更重要的 是计算机广泛地应用于情报检索、企业管理、系统工程等方面,已远 远超出了科技计算的范围,而渗透到人类社会活动的一切领域。与此 相应,计算机的处理对象也从简单的纯数值性信息发展到非数值性的 和具有一定结构的信息。
• 为了叙述上的方便和避免产生混淆,通常我们把数据的逻辑结构
统称为数据结构,把数据的物理结构统称为存储结构( Storage Structure)。
2018/10/9
华侨大学数学系 黄建新
四种基本基本结构: (1)集合:结构中的数据元素之间除了“同属于一个集合”的关 系外,别无其他关系。 (2)线性结构:结构中的数据元素之间存在一个对一个的关系。 如:图书馆的书目检索系统 (3)树形结构:结构中的数据元素存在一个对多个的关系。 如:计算机和人对奕问题 工厂的组织管理 (4)图状结构:结构中的数据元素存在多个对多个的关系。 如:多叉路口的交通灯管理问题 最短路径问题
2018/10/9
华侨大学数学系 黄建新
1.3 什么是数据结构
• 计算机解决一个具体问题时,大致需要经过下列几个步骤:首先
要从具体问题中抽象出一个适当的数学模型,然后设计一个解此 数学模型的算法(Algorithm),最后编出程序、进行测试、调整 直至得到最终解答。寻求数学模型的实质是分析问题,从中提取 操作的对象,并找出这些操作对象之间含有的关系,然后用数学 的语言加以描述。 • 计算机算法与数据的结构密切相关,算法无不依附于具体的数据 结构,数据结构直接关系到算法的选择和效率。 • 运算是由计算机来完成,这就要设计相应的插入、删除和修改的 算法 。也就是说,数据结构还需要给出每种结构类型所定义的各 种运算的算法。 • 直观定义:数据结构是研究程序设计中计算机操作的对象以及它 们之间的关系和运算的一门学科。
数据结构(C语言版本)
数据结构的形式定义:数据结构是一个二元组 data_structure=(D,S)
其中:D是数据元素的有限集,S是D上关系的有限集。
2023/11/3
例1 一种结构 lineority=(K,R) K={k1,k2,kHale Waihona Puke ,k4,k5,k6,k7} R={r}
• 众所周知,二十世纪四十年代,电子数字计算机问世的直接原因是解
决弹道学的计算问题。早期,电子计算机的应用范围,几乎只局限于 科学和工程的计算,其处理的对象是纯数值性的信息,通常,人们把 这类问题称为数值计算。
• 近三十年来,电子计算机的发展异常迅猛,这不仅表现在计算机本身
运算速度不断提高、信息存储量日益扩大、价格逐步下降,更重要的 是计算机广泛地应用于情报检索、企业管理、系统工程等方面,已远 远超出了科技计算的范围,而渗透到人类社会活动的一切领域。与此 相应,计算机的处理对象也从简单的纯数值性信息发展到非数值性的 和具有一定结构的信息。
4.存储结构
• 数据在计算机中的存储表示称为数据的存储结构。 • 在表1-1所示的表格数据在计算机中可以有多种存储表示,例如,
可以表示成数组,存放在内存中;也可以表示成文件,存放在磁 盘上,等等。
2023/11/3
5.数据处理
• 数据处理是指对数据进行查找、插入、删除、合并、排序、统计
以及简单计算等的操作过程。在早期,计算机主要用于科学和工 程计算,进入八十年代以后,计算机主要用于数据处理。据有关 统计资料表明,现在计算机用于数据处理的时间比例达到80%以 上,随着时间的推移和计算机应用的进一步普及,计算机用于数 据处理的时间比例必将进一步增大。
数据结构 C语言版(严蔚敏版)第7章 图
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 重合, 则称这样的路径为回路或环。
数据结构(C语言版)
数据结构(C语言版) 数据结构(C语言版)1.简介1.1 什么是数据结构1.2 数据结构的作用1.3 数据结构的分类1.4 C语言中的数据结构2.线性表2.1 数组2.2 链表2.2.1 单链表2.2.2 双链表2.2.3 循环链表3.栈与队列3.1 栈3.1.1 栈的定义3.1.2 栈的基本操作3.2 队列3.2.1 队列的定义3.2.2 队列的基本操作4.树4.1 二叉树4.1.1 二叉树的定义4.1.2 二叉树的遍历4.2 AVL树4.3 B树5.图5.1 图的定义5.2 图的存储方式5.2.1 邻接矩阵5.2.2 邻接表5.3 图的遍历算法5.3.1 深度优先搜索(DFS)5.3.2 广度优先搜索(BFS)6.散列表(哈希表)6.1 散列函数6.2 散列表的冲突解决6.2.1 开放寻址法6.2.2 链地质法7.排序算法7.1 冒泡排序7.2 插入排序7.3 选择排序7.4 快速排序7.5 归并排序7.6 堆排序7.7 计数排序7.8 桶排序7.9 基数排序8.算法分析8.1 时间复杂度8.2 空间复杂度8.3 最好、最坏和平均情况分析8.4 大O表示法附件:________无法律名词及注释:________●数据结构:________指数据元素之间的关系,以及对数据元素的操作方法的一种组织形式。
●C语言:________一种通用的编程语言,用于系统软件和应用软件的开发。
●线性表:________由n个具有相同特性的数据元素组成的有限序列。
●栈:________一种特殊的线性表,只能在表的一端插入和删除数据,遵循后进先出(LIFO)的原则。
●队列:________一种特殊的线性表,只能在表的一端插入数据,在另一端删除数据,遵循先进先出(FIFO)的原则。
●树:________由n(n>=0)个有限节点组成的集合,其中有一个称为根节点,除根节点外,每个节点都有且仅有一个父节点。
●图:________由顶点的有穷集合和边的集合组成,通常用G(V, E)表示,其中V表示顶点的有穷非空集合,E表示边的有穷集合。
图的邻接多重表和搜索(C++版本)
图的邻接多重表和搜索(C++版本)最近在学数据结构,学到图这⼀章,⽹上的C++版本的代码乱得不⾏,所以⾃⼰写了⼀个完整C++版本的放这⾥。
⽤邻接多重表表⽰⼀个⽆向图,并给出DFS和BFS搜索代码。
邻接多重表好处就是贼直观,⼏条边就⼏个边表的元素。
代码如下:边表节点定义(其实就是边的定义)typedef struct EdgeNode //邻接多重表{int iVertex;EdgeNode* iLink;int jVertex;EdgeNode* jLink;};顶点表节点的定义template <typename Type>struct VextexNode //邻接多重表的顶点表{Type Data;EdgeNode* TailLink;Mark Flag;};最后是图的模板类#ifndef MULADJACENCYLIST_H#define MULADJACENCYLIST_H#include "SideNode.h"#include "VexNode.h"#include <iostream>#include <vector>#include <list>#include <set>using namespace std;template <typename Type, int N>class MulAdjacencyList{public:MulAdjacencyList();~MulAdjacencyList();void AddEdge();int DeleteEdge(int x, int y);void DFS(int x, const Type& Value);void BFS(int x, const Type& Value);private:int InitEdgeNum(); //构造函数中先输⼊图的边数int NextIndex(int CurIndex); //查找最近的⼀个邻接点,CurIndex为点的下标⽽不是值void BFSHelper(set <int> SourceList, const Type& Value); //BFS真正的递归函数void AllNextIndex(int i); //和i相连的所有邻接点,i为点的下标⽽不是值VextexNode <Type> VertexArray[N]; //顶点表EdgeNode* LastPtr(int x);int EdgeNums; //当前的边数vector <int> Temp; //⽤来存放搜索结果的容器set <int> TempList; //⽤来存放AllNextIndex结果的容器};template <typename Type, int N>void MulAdjacencyList<Type, N>::AddEdge() //添加⼀条x到y的⽆向边{cout << "Enter the edge wanna insert!" << endl;int i, j;if (cin >> i >> j){EdgeNode* TarPtr = new EdgeNode;TarPtr->iVertex = i;TarPtr->jVertex = j;TarPtr->iLink = VertexArray[i].TailLink;TarPtr->jLink = VertexArray[j].TailLink;VertexArray[i].TailLink = TarPtr;VertexArray[j].TailLink = TarPtr;EdgeNums++;}elsecin.clear();}template <typename Type, int N>int MulAdjacencyList<Type, N>::InitEdgeNum(){cout << "Enter the quantity of edges!"<< endl;cin >> EdgeNums;return EdgeNums;}template <typename Type, int N>EdgeNode* MulAdjacencyList<Type, N>::LastPtr(int x) //找到和x相关的最后⼀条边{EdgeNode* Temp = VertexArray[x].TailLink;EdgeNode* LastTemp = Temp;while (Temp != NULL){if (Temp->iVertex == x){LastTemp = Temp;Temp = Temp->iLink;}else if (Temp->jVertex == x){LastTemp = Temp;Temp = Temp->jLink;}}return LastTemp;}template <typename Type, int N>MulAdjacencyList <Type, N>::MulAdjacencyList(){cout << "enter the vertex for the graph!" << endl;for (int i = 0; i != N; ++i){cin >> VertexArray[i].Data;VertexArray[i].TailLink = NULL;VertexArray[i].Flag = No;}int Temp = InitEdgeNum();for (int i = 0; i != Temp; ++ i)AddEdge();}template <typename Type, int N>int MulAdjacencyList<Type, N>::DeleteEdge(int x, int y) //删除x到y的⼀条⽆向边{if (x == y)return0;EdgeNode* Q = VertexArray[x].TailLink; //Q的下⼀条边就是要删除的边EdgeNode* P = VertexArray[x].TailLink; //先从x出发找到要删除的边,调整完x的边的次序,得到指针,最后再删除if (P && P->jVertex == y) //假如第⼀条边就是待删除的边, P是前向判断,避免P为NULL的情况下还执⾏P->jVertex VertexArray[x].TailLink = P->iLink;else if (P && P->iVertex == y)VertexArray[x].TailLink = P->jLink;else//假如第⼀条边不是要删除的边,则向下查找{while (P){if (P->iVertex == x && P->jVertex != y)//不是要删除的边{Q = P;P = P->iLink;}else if (P->jVertex == x && P->iVertex != y){Q = P;P = P->jLink;}else//找到了邻接点ybreak;}if (P == NULL){return0; //这⾥可以加⼊⼀句警告“Not Found”}else if (P->iVertex == x && P->jVertex == y) //找到了边(x,y),调整x的边的次序{if (Q->iVertex == x)Q->iLink = P->iLink;elseQ->jLink = P->iLink;}else if (P->iVertex == y && P->jVertex == x){if (Q->iVertex == x)Q->iLink = P->jLink;elseQ->jLink = P->jLink;}}P = VertexArray[y].TailLink; //从y出发开始查找,调整y的边的次序if (P && P->iVertex == x)VertexArray[y].TailLink = P->jLink;else if (P && P->jVertex == x)VertexArray[y].TailLink = P->iLink;else{while (P != NULL){if (P->iVertex == y && P->jVertex != x){Q = P;P = P->iLink;}else if (P->jVertex == y && P->iVertex != x){Q = P;P = P->jLink;}elsebreak;}if (P == NULL) //由于上⾯打了⼀次警告,这⾥就不打警告了return0;else if (P->iVertex == y && P->jVertex == x){if (Q->iVertex == y)Q->iLink = P->iLink;elseQ->jLink = P->iLink;}else if ((P->jVertex == y && P->iVertex == x)){if (Q->iVertex == y)Q->iLink = P->jLink;elseQ->jLink = P->jLink;}}cout << x << endl << y << endl<<"yici"<<endl;if (P != NULL) delete P; //调整完线序了,删掉边--EdgeNums;return1;}template <typename Type, int N>MulAdjacencyList <Type, N>::~MulAdjacencyList(){for (int i = 0; i != N; ++i){for (int j = 0; j != N; ++j)DeleteEdge(i,j);}}template <typename Type, int N>void MulAdjacencyList <Type, N>::AllNextIndex(int i) //找到和i相关联的所有的点{EdgeNode* Ptr = VertexArray[i].TailLink;while (Ptr != NULL){if (Ptr->iVertex == i){if (VertexArray[Ptr->jVertex].Flag != Yes)TempList.insert(Ptr->jVertex); Ptr = Ptr->iLink;}else{if (VertexArray[Ptr->iVertex].Flag != Yes)TempList.insert(Ptr->iVertex); Ptr = Ptr->jLink;}}}template <typename Type, int N>int MulAdjacencyList <Type, N>::NextIndex(int CurIndex){EdgeNode* Ptr = VertexArray[CurIndex].TailLink;while (Ptr != NULL){if (Ptr->iVertex == CurIndex){if (VertexArray[Ptr->jVertex].Flag == No){return Ptr->jVertex;}elsePtr = Ptr->iLink;}else if (Ptr ->jVertex == CurIndex){if (VertexArray[Ptr->iVertex].Flag == No){return Ptr->iVertex;}elsePtr = Ptr->jLink;}}if (Ptr == NULL) { return N; }}template <typename Type, int N>void MulAdjacencyList <Type, N>::DFS(int x, const Type& Value) //x为起始的下标,Value为查找的值{if (VertexArray[x].Data == Value){Temp.push_back(x);}VertexArray[x].Flag = Yes;int TempIndex = NextIndex(x);while (TempIndex != N){DFS(TempIndex, Value);TempIndex = NextIndex(x);}for (vector <int>::const_iterator i = A.Temp.begin(); i != A.Temp.end(); ++i) //打印找到的元素cout << *i << endl;}template <typename Type, int N>void MulAdjacencyList <Type, N>::BFSHelper(set <int> SourceList,const Type& Value){if (!SourceList.empty()){for (set <int>::const_iterator i = SourceList.begin(); i != SourceList.end(); ++i){VertexArray[*i].Flag = Yes;if (VertexArray[*i].Data == Value)Temp.push_back(*i);}for (set <int>::const_iterator i = SourceList.begin(); i != SourceList.end(); ++i){AllNextIndex(*i);}SourceList = TempList;TempList.clear();BFSHelper(SourceList, Value);}}template <typename Type, int N>void MulAdjacencyList <Type, N>::BFS(int x, const Type& Value){set <int> Set;Set.insert(x);BFSHelper(Set, Value);}#endif⼤类的代码有点乱,先挖个坑以后有空再来填上,希望对各位和⾃⼰有帮助。
C语言中的数据结构与算法实现
C语言中的数据结构与算法实现数据结构与算法是计算机科学中非常重要的概念,它们在程序设计中起着至关重要的作用。
在C语言中,我们可以利用各种数据结构和算法来实现一些复杂的功能和解决问题。
下面我将介绍C语言中常见的数据结构和算法,并举例说明它们的实现方法。
一、数据结构1. 数组:在C语言中,数组是最基本的数据结构之一。
数组是一种线性数据结构,它可以存储相同类型的元素,并通过下标访问。
例如,我们可以通过数组实现一维、二维甚至多维的数据结构。
2. 链表:链表是另一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
链表可以分为单向链表、双向链表和循环链表等不同类型。
通过链表我们可以实现插入、删除等操作。
3. 栈和队列:栈和队列是两种基本的线性数据结构。
栈是“先进后出”的数据结构,只能在栈顶进行插入和删除操作;队列是“先进先出”的数据结构,只能在队首和队尾进行插入和删除操作。
4. 树:树是一种非线性的数据结构,它由节点和边组成,可以表示层次关系。
二叉树是树的一种特殊形式,每个节点最多有两个子节点。
二叉搜索树是一种特殊的二叉树,左子树的节点都小于根节点,右子树的节点都大于根节点。
5. 图:图是一种复杂的非线性数据结构,由节点和边组成。
图可以分为有向图和无向图,常用于表示各种关系。
二、算法1. 排序算法:排序算法是最基本的算法之一,在实际开发中经常会用到。
常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序等。
这些排序算法具有不同的时间复杂度和空间复杂度,可以根据实际需求选择适合的排序算法。
2. 查找算法:查找算法用于在数据集中查找指定元素。
常见的查找算法有顺序查找、二分查找、哈希查找等。
二分查找是最高效的查找算法之一,时间复杂度为O(logn)。
3. 图算法:图算法用于解决与图相关的问题,如最短路径、最小生成树等。
常见的图算法有Dijkstra算法、Prim算法、Kruskal算法等。
数据结构实用教程(c语言版)
队列
03
CHAPTER
高级数据结构
树的概念
树是一种抽象数据类型,用于表示具有层次关系的数据。树中的每个节点可以有多个子节点,但只能有一个父节点。
树的遍历
树有多种遍历方式,包括前序遍历、中序遍历和后序遍历。这些遍历方式可以用于查找、修改或删除树中的节点。
二叉树
二叉树是一种特殊的树,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树有多种实现方式,如二叉搜索树、AVL树和红黑树等。
01
02
03
图
哈希表的概念
哈希表是一种使用哈希函数将键映射到桶中的数据结构。哈希表提供了快速的插入、删除和查找操作。
一个好的哈希函数可以将键均匀地映射到桶中,以减少冲突和提高哈希表的性能。常见的哈希函数有除法哈希、乘法哈希和平方哈希等。
当两个不同的键映射到同一个桶时,会发生哈希冲突。常见的处理冲突的方法有开放寻址法(如线性探测或二次探测)和链地址法(将冲突的键值对存储在同一个桶中)。
数据结构实用教程(C语言版)
目录
数据结构基础 基本数据结构 高级数据结构 数据结构操作 数据结构应用 数据结构优化
01
CHAPTER
数据结构基础
数据结构是数据的组织、排列和表示的方式,它涉及到数据的逻辑关系和物理存储。数据结构是计算机科学中的基本概念,用于解决实际问题中的数据处理和信息管理。
数据结构定义
例如,在排序算法中,可以使用分治法将大问题分解为小问题来解决,如归并排序;在搜索算法中,可以使用回溯法、分治法等策略来解决问题。
在动态规划中,可以使用自底向上、自顶向下等方法来解决问题,其中自底向上方法可以减少重复计算,提高算法效率。
算法优化
THANKS
数据结构 邻接多重表
数据结构邻接多重表
邻接多重表是一种常用的图的存储结构,它解决了邻接表和邻接矩阵两种结构在一些场景下的缺点。
邻接多重表的基本思想是使用一个顶点表和一个边表来分别存储图的顶点和边的信息。
在邻接多重表中,顶点表中的每个节点包含两个指针,一个指向该顶点的第一条边,另一个指向该顶点在顶点表中的下一个顶点。
边表中的每个节点包含四个字段,分别是起始顶点、终止顶点、指向起始顶点的下一条边和指向终止顶点的下一条边。
这样,通过顶点表和边表的结构,可以有效地表示图的结构信息。
邻接多重表的优点是可以高效地插入和删除边,因为每条边都在边表中作为一个节点存在,不需要像邻接矩阵那样重新调整矩阵的大小。
同时,邻接多重表也能够比较容易地访问一个顶点的所有邻接点。
然而,邻接多重表的缺点是在查找某条边时效率较低,因为需要遍历边表。
此外,由于邻接多重表需要维护两个表的结构,所以对于某些操作可能会比较复杂。
总之,邻接多重表是一种适用于某些特定场景下的图的存储结构,它在实际应用中能够提供高效的插入和删除操作,但在查找边的操作上可能会略显不足。
数据结构 邻接多重表
数据结构邻接多重表
摘要:
1.邻接多重表的定义
2.邻接多重表的优点
3.邻接多重表的缺点
4.邻接多重表的应用实例
5.邻接多重表的构建方法
正文:
邻接多重表是一种用于表示有向图或无向图中各个顶点之间关系的数据结构,它是图论中常见的一种数据表示方法。
与邻接矩阵不同,邻接多重表可以更加直观地表示图中的顶点之间的关系,因此在实际应用中具有更高的灵活性和可读性。
邻接多重表的优点主要体现在以下几点:
1.能够清晰地表示图中各个顶点之间的关系,便于理解和分析;
2.存储空间相对较小,因为只需要存储实际存在的边;
3.便于实现图的遍历和搜索算法,如深度优先搜索和广度优先搜索等。
尽管邻接多重表具有以上优点,但同时也存在一些缺点,例如:
1.邻接多重表的构建和维护相对邻接矩阵较为复杂;
2.当图中顶点数量较大时,邻接多重表的存储空间也会相应增加,导致计算效率降低。
邻接多重表在实际应用中具有广泛的应用,例如在社交网络分析、电路设
计、生物信息学等领域均有涉及。
一个典型的应用实例是利用邻接多重表表示一个有向图,通过对图进行遍历和搜索,可以找到从一个顶点到另一个顶点的最短路径。
邻接多重表的构建方法通常分为以下几步:
1.创建一个空的邻接多重表,用于存储图中的顶点及其邻接关系;
2.遍历图中的每一条边,将边的起点和终点以及边的权值添加到邻接多重表中;
3.对于有向图,需要分别创建一个入边表和一个出边表,以记录每个顶点的入边和出边关系;
4.对于无向图,则可以将邻接多重表中的每一条边视为双向边。
总之,邻接多重表作为一种重要的数据结构,具有灵活性高、可读性强等优点,广泛应用于图论及其相关领域。
建立无向图的邻接多重表
题目:编写一个算法由依次输入的顶点数目,边的数目,各顶点的信息和各条边的信息建立无向图的邻接多重表。
一.需求分析这里需要两个主要字函数,一个是建立图,另一个是打印图。
二.概要设计首先是建立两个结点,一个是边结点,另一个是顶点结点,分别为struct Edge,struct Node,然后建立图,Create_ML_Graph(int Vertex1,NextEdge New),紧接着是打印Print_ML_Graph(struct Node *Head)。
三.详细设计#include <stdlib.h>#include <stdio.h>#define VertexNum 6#define NULL ((void *)0)struct Edge{int Marked;int Vertex1;int Vertex2;struct Edge *Edge1;struct Edge *Edge2;};typedef struct Edge *NextEdge;struct Node{int Vertex;struct Edge *Next;};typedef struct Node *Graph;struct Node Head[VertexNum];void Create_ML_Graph(int Vertex1,NextEdge New){NextEdge Pointer;NextEdge Previous;Previous=NULL;Pointer=Head[Vertex1].Next;while(Pointer!=NULL){Previous=Pointer;if (Pointer->Vertex1==Vertex1)Pointer=Pointer->Edge1;else Pointer=Pointer->Edge2;}if(Previous==NULL)Head[Vertex1].Next=New;else if(Previous->Vertex1==Vertex1)Previous->Edge1=New;else Previous->Edge2=New;}void Print_ML_Graph(struct Node *Head) {NextEdge Pointer;Pointer=Head->Next;while( Pointer!=NULL){printf("(%d,%d)",Pointer->Vertex1,Pointer->Vertex2); if(Head->Vertex==Pointer->Vertex1)Pointer=Pointer->Edge1;else if(Head->Vertex==Pointer->Vertex2)Pointer=Pointer->Edge2;}printf("\n");}void main(){int Source;int Destinition;int Choose;NextEdge New;int i;for(i=0;i<VertexNum;i++){Head[i].Vertex=i;Head[i].Next=NULL;}printf("1.Undirected Graph\n");printf("2.Directed Graph\n");printf("Please choose:");scanf("%d",&Choose);while(1){printf("Please input the Edge's source:");scanf("%d",&Source);if(Source==-1) break;printf("Please input the Edge's Destinition:");scanf("%d",&Destinition);if(Source>=VertexNum||Destinition>=VertexNum) printf("@Error@:out of range!!\n");else{ New=(NextEdge) malloc(sizeof(struct Edge));if(New!=NULL){New->Vertex1=Source;New->Vertex2=Destinition;New->Edge1=NULL;New->Edge2=NULL;Create_ML_Graph(Destinition,New);}}}printf("##Graph##\n");for(i=0;i<VertexNum;i++){printf("Vertex[%d]:",i);Print_ML_Graph(&Head[i]);}}四.调试分析这个题在调试时,除了常规的变量的定义和指针等错误外,主要是指针的值传不过去,导致打印的时候输入的图打印不出来,检查的时候看各指针是不是传过去了(用单步执行)。
邻接表及其实现_数据结构(C语言版)(第3版)_[共2页]
作的具体函数请查阅C语言相关资料)。
若从键盘输入图的相关信息,只需对算法8.1稍作修改,删除打开与关闭文件的相关操作,将文件输入语句改为键盘输入语句即可。
当建立网络存储结构时,边信息以三元组(i,j,w)的形式输入,i、j分别表示两顶点的序号,w表示边上的权。
例如,对图8.6所示的无向网络G7,设其对应的输入文件名为G7.txt,其内容是:4 401230 1 560 2 340 3 782 3 254 4表示该图包括4个顶点4条边,字符0123表示顶点V0,V1,V2,V3的结点信息,其他的4个三元组代表4条边信息。
通过函数调用creat(&g,“g7.txt”,0)便可建立无向网G7的邻接矩阵。
当参数c=1时,将建立有向图的存储结构。
当建立非网络的存储结构时,所有的边信息只需按二元组(i,j)的形式输入,边的权值取值为0或1。
8.3.2 邻接表及其实现用邻接矩阵表示法存储图,占用的存储单元个数只与图中顶点的个数有关,而与边的数目无关。
一个含有n个顶点的图,如果其边数比n2少得多,那么它的邻接矩阵就会有很多空元素,浪费了存储空间。
这时可以采用图的另一种存储结构—邻接表表示法。
图的邻接表表示法类似于树的孩子链表表示法。
对于图G中的每个顶点v i,该方法把所有邻接于v i的顶点v j链成一个带头结点的单链表,这个单链表就称为顶点v i的邻接表。
单链表中的每个结点至少包含两个域,一个为邻接点域(adjvex),它指示与顶点v i邻接的顶点在图中的位序,另一个为链域(next),它指示与顶点v i邻接的下一个结点。
如果是网络,可以在单链表的结点中增加一个数据域用于存储和边(弧)相关的信息,如权值等。
在每个链表上需附设一个表头结点,在表头结点中,除了设有头指针域(firstedge)指向链表中第一个结点之外,还设有存储顶点v i的数据域(vertex)或其他有关信息的数据域。
头结点与链表结点的结构可表示为:头结点表结点vertex firstedge adjvex next为了便于随机访问任意顶点的邻接表,可将所有头结点顺序存储在一个向量中就构成了图的邻接表存储。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构C语言版无向图的邻接多重表存储表示和实现.txt只要你要,只要我有,你还外边转什么阿老实在我身边待着就行了。
听我的就是,问那么多干嘛,我在你身边,你还走错路!跟着我!不能给你幸福是我的错,但谁让你不幸福,我TMD去砍了他/* 数据结构C语言版无向图的邻接多重表存储表示和实现P166编译环境:Dev-C++ 4.9.9.2日期:2011年2月15日*/#include <stdio.h>#include <malloc.h>#define MAX_NAME 3 // 顶点字符串的最大长度+1#define MAX_INFO 80 // 相关信息字符串的最大长度+1typedef char InfoType;typedef char VertexType[MAX_NAME]; // 字符串类型// AMLGraph.h 无向图的邻接多重表存储表示#define MAX_VERTEX_NUM 20typedef enum{unvisited,visited}VisitIf;typedef struct EBox{VisitIf mark; // 访问标记int ivex,jvex; // 该边依附的两个顶点的位置struct EBox *ilink,*jlink; // 分别指向依附这两个顶点的下一条边InfoType *info; // 该边信息指针}EBox;typedef struct{VertexType data;EBox *firstedge; // 指向第一条依附该顶点的边}VexBox;typedef struct{VexBox adjmulist[MAX_VERTEX_NUM];int vexnum,edgenum; // 无向图的当前顶点数和边数}AMLGraph;typedef int QElemType;// 单链队列--队列的链式存储结构typedef struct QNode{QElemType data; //数据域struct QNode *next; //指针域}QNode,*QueuePtr;typedef struct{QueuePtr front,//队头指针,指针域指向队头元素rear; //队尾指针,指向队尾元素}LinkQueue;// 若G中存在顶点u,则返回该顶点在无向图中位置;否则返回-1int LocateVex(AMLGraph G,VertexType u){int i;for(i=0;i<G.vexnum;++i)if(strcmp(u,G.adjmulist[i].data)==0)return i;return -1;}// 采用邻接多重表存储结构,构造无向图Gint CreateGraph(AMLGraph *G){int i,j,k,l,IncInfo;char s[MAX_INFO];VertexType va,vb;EBox *p;printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");scanf("%d,%d,%d",&(*G).vexnum,&(*G).edgenum,&IncInfo);printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);for(i=0;i<(*G).vexnum;++i) // 构造顶点向量{scanf("%s",(*G).adjmulist[i].data);(*G).adjmulist[i].firstedge=NULL;}printf("请顺序输入每条边的两个端点(以空格作为间隔):\n");for(k=0;k<(*G).edgenum;++k) // 构造表结点链表{scanf("%s%s%*c",va,vb); // %*c吃掉回车符i=LocateVex(*G,va); // 一端j=LocateVex(*G,vb); // 另一端p=(EBox*)malloc(sizeof(EBox));p->mark=unvisited; // 设初值p->ivex=i;p->jvex=j;p->info=NULL;p->ilink=(*G).adjmulist[i].firstedge; // 插在表头(*G).adjmulist[i].firstedge=p;p->jlink=(*G).adjmulist[j].firstedge; // 插在表头(*G).adjmulist[j].firstedge=p;if(IncInfo) // 边有相关信息{printf("请输入该弧的相关信息(<%d个字符):",MAX_INFO);gets(s);l=strlen(s);if(l){p->info=(char*)malloc((l+1)*sizeof(char));strcpy(p->info,s);}}}return 1;}// 返回v的值VertexType* GetVex(AMLGraph G,int v){if(v>=G.vexnum||v<0)exit(0);return &G.adjmulist[v].data;}// 对v赋新值valueint PutVex(AMLGraph *G,VertexType v,VertexType value){int i;i=LocateVex(*G,v);if(i<0) // v不是G的顶点return 0;strcpy((*G).adjmulist[i].data,value);return 1;}// 返回v的第一个邻接顶点的序号。
若顶点在G中没有邻接顶点,则返回-1int FirstAdjVex(AMLGraph G,VertexType v){int i;i=LocateVex(G,v);if(i<0)return -1;if(G.adjmulist[i].firstedge) // v有邻接顶点if(G.adjmulist[i].firstedge->ivex==i)return G.adjmulist[i].firstedge->jvex;elsereturn G.adjmulist[i].firstedge->ivex;elsereturn -1;}// 返回v的(相对于w的)下一个邻接顶点的序号。
若w是v的最后一个邻接点,则返回-1 int NextAdjVex(AMLGraph G,VertexType v,VertexType w){int i,j;EBox *p;i=LocateVex(G,v); // i是顶点v的序号j=LocateVex(G,w); // j是顶点w的序号if(i<0||j<0) // v或w不是G的顶点return -1;p=G.adjmulist[i].firstedge; // p指向顶点v的第1条边while(p)if(p->ivex==i&&p->jvex!=j) // 不是邻接顶点w(情况1)p=p->ilink; // 找下一个邻接顶点else if(p->jvex==i&&p->ivex!=j) // 不是邻接顶点w(情况2)p=p->jlink; // 找下一个邻接顶点else // 是邻接顶点wbreak;if(p&&p->ivex==i&&p->jvex==j) // 找到邻接顶点w(情况1){p=p->ilink;if(p&&p->ivex==i)return p->jvex;else if(p&&p->jvex==i)return p->ivex;}if(p&&p->ivex==j&&p->jvex==i) // 找到邻接顶点w(情况2){p=p->jlink;if(p&&p->ivex==i)return p->jvex;else if(p&&p->jvex==i)return p->ivex;}return -1;}// 在G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) int InsertVex(AMLGraph *G,VertexType v){if((*G).vexnum==MAX_VERTEX_NUM) // 结点已满,不能插入return 0;if(LocateVex(*G,v)>=0) // 结点已存在,不能插入return 0;strcpy((*G).adjmulist[(*G).vexnum].data,v);(*G).adjmulist[(*G).vexnum].firstedge=NULL;(*G).vexnum++;return 1;}// 在G中删除弧<v,w>int DeleteArc(AMLGraph *G,VertexType v,VertexType w){int i,j;EBox *p,*q;i=LocateVex(*G,v);j=LocateVex(*G,w);if(i<0||j<0||i==j)return 0; // 图中没有该点或弧// 以下使指向待删除边的第1个指针绕过这条边p=(*G).adjmulist[i].firstedge; // p指向顶点v的第1条边if(p&&p->jvex==j) // 第1条边即为待删除边(情况1)(*G).adjmulist[i].firstedge=p->ilink;else if(p&&p->ivex==j) // 第1条边即为待删除边(情况2) (*G).adjmulist[i].firstedge=p->jlink;else // 第1条边不是待删除边{while(p) // 向后查找弧<v,w>{if(p->ivex==i&&p->jvex!=j) // 不是待删除边{q=p;p=p->ilink; // 找下一个邻接顶点}else if(p->jvex==i&&p->ivex!=j) // 不是待删除边{q=p;p=p->jlink; // 找下一个邻接顶点}else // 是邻接顶点wbreak;}if(!p) // 没找到该边return 0;if(p->ivex==i&&p->jvex==j) // 找到弧<v,w>(情况1) if(q->ivex==i)q->ilink=p->ilink;elseq->jlink=p->ilink;else if(p->ivex==j&&p->jvex==i) // 找到弧<v,w>(情况2) if(q->ivex==i)q->ilink=p->jlink;elseq->jlink=p->jlink;}// 以下由另一顶点起找待删除边且删除之p=(*G).adjmulist[j].firstedge; // p指向顶点w的第1条边if(p->jvex==i) // 第1条边即为待删除边(情况1){(*G).adjmulist[j].firstedge=p->ilink;if(p->info) // 有相关信息free(p->info);free(p);}else if(p->ivex==i) // 第1条边即为待删除边(情况2){(*G).adjmulist[j].firstedge=p->jlink;if(p->info) // 有相关信息free(p->info);free(p);}else // 第1条边不是待删除边{while(p) // 向后查找弧<v,w>if(p->ivex==j&&p->jvex!=i) // 不是待删除边{q=p;p=p->ilink; // 找下一个邻接顶点}else if(p->jvex==j&&p->ivex!=i) // 不是待删除边{q=p;p=p->jlink; // 找下一个邻接顶点}else // 是邻接顶点vbreak;if(p->ivex==i&&p->jvex==j) // 找到弧<v,w>(情况1){if(q->ivex==j)q->ilink=p->jlink;elseq->jlink=p->jlink;if(p->info) // 有相关信息free(p->info);free(p);}else if(p->ivex==j&&p->jvex==i) // 找到弧<v,w>(情况2) {if(q->ivex==j)q->ilink=p->ilink;elseq->jlink=p->ilink;if(p->info) // 有相关信息free(p->info);free(p);}}(*G).edgenum--;return 1;// 删除G中顶点v及其相关的边int DeleteVex(AMLGraph *G,VertexType v){int i,j;VertexType w;EBox *p;i=LocateVex(*G,v); // i为待删除顶点的序号if(i<0)return 0;for(j=0;j<(*G).vexnum;j++) // 删除与顶点v相连的边(如果有的话) {if(j==i)continue;strcpy(w,*GetVex(*G,j)); // w是第j个顶点的值DeleteArc(G,v,w);}for(j=i+1;j<(*G).vexnum;j++) // 排在顶点v后面的顶点的序号减1 (*G).adjmulist[j-1]=(*G).adjmulist[j];(*G).vexnum--; // 顶点数减1for(j=i;j<(*G).vexnum;j++) // 修改顶点的序号{p=(*G).adjmulist[j].firstedge;if(p){if(p->ivex==j+1){p->ivex--;p=p->ilink;}else{p->jvex--;p=p->jlink;}}}return 1;}void DestroyGraph(AMLGraph *G)int i;for(i=(*G).vexnum-1;i>=0;i--)DeleteVex(G,(*G).adjmulist[i].data);}// 在G中增添弧<v,w>int InsertArc(AMLGraph *G,VertexType v,VertexType w){int i,j,l,IncInfo;char s[MAX_INFO];EBox *p;i=LocateVex(*G,v); // 一端j=LocateVex(*G,w); // 另一端if(i<0||j<0)return 0;p=(EBox*)malloc(sizeof(EBox));p->mark=unvisited;p->ivex=i;p->jvex=j;p->info=NULL;p->ilink=(*G).adjmulist[i].firstedge; // 插在表头(*G).adjmulist[i].firstedge=p;p->jlink=(*G).adjmulist[j].firstedge; // 插在表头(*G).adjmulist[j].firstedge=p;printf("该边是否有相关信息(1:有 0:无): ");scanf("%d%*c",&IncInfo); // 吃掉回车符if(IncInfo) // 边有相关信息{printf("请输入该边的相关信息(<%d个字符):",MAX_INFO);gets(s);l=strlen(s);if(l){p->info=(char*)malloc((l+1)*sizeof(char));strcpy(p->info,s);}}(*G).edgenum++;return 1;}int visite[MAX_VERTEX_NUM]; // 访问标志数组(全局量)int(*VisitFunc)(VertexType v);void DFS(AMLGraph G,int v){int j;EBox *p;VisitFunc(G.adjmulist[v].data);visite[v]=1;p=G.adjmulist[v].firstedge;while(p){j=p->ivex==v?p->jvex:p->ivex;if(!visite[j])DFS(G,j);p=p->ivex==v?p->ilink:p->jlink;}}// 算法7.4// 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visitvoid DFSTraverse(AMLGraph G,int(*visit)(VertexType)){int v;VisitFunc=visit;for(v=0;v<G.vexnum;v++)visite[v]=0;for(v=0;v<G.vexnum;v++)if(!visite[v])DFS(G,v);printf("\n");}// 构造一个空队列Qint InitQueue(LinkQueue *Q){(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode)); //动态分配一个空间if(!(*Q).front)exit(0);(*Q).front->next=NULL; //队头指针指向空,无数据域,这样构成了一个空队列return 1;}// 若Q为空队列,则返回1,否则返回0int QueueEmpty(LinkQueue Q){if(Q.front==Q.rear)return 1;elsereturn 0;}// 插入元素e为Q的新的队尾元素int EnQueue(LinkQueue *Q,QElemType e){QueuePtr p=(QueuePtr)malloc(sizeof(QNode));if(!p) // 存储分配失败exit(0);//生成一个以为e为数据域的队列元素p->data=e;p->next=NULL;//将该新队列元素接在队尾的后面(*Q).rear->next=p;(*Q).rear=p;return 1;}// 若队列不空,删除Q的队头元素,用e返回其值,并返回1,否则返回0 int DeQueue(LinkQueue *Q,QElemType *e){QueuePtr p;if((*Q).front==(*Q).rear)return 0;p=(*Q).front->next; //队头元素*e=p->data;(*Q).front->next=p->next;if((*Q).rear==p)(*Q).rear=(*Q).front;free(p);return 1;}// 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数// Visit一次且仅一次。