第1关:图的邻接表存储及求邻接点操作
任务描述
本关任务:要求从文件输入顶点和边数据,包括顶点信息、边、权值等,编写程序实现以下功能。
1)构造图G的邻接表和顶点集,即图的存储结构为邻接表。
2)输出图G的各顶点和邻接表。
3)输出图G中某个顶点的所有邻接顶点。
测试说明
平台会对你编写的代码进行测试:
测试输入:
3
lt.txt
徐州
输入说明:
第一行输入3,表示输入图的类型为无向网。
第二行输入文件名,该文件里保存了图的数据信息,内容如下:
测试说明
平台会对你编写的代码进行测试:
测试输入:
3
lt.txt
徐州
输入说明:
第一行输入3,表示输入图的类型为无向网。
第二行输入文件名,该文件里保存了图的数据信息,内容如下:
第1行为图的顶点的个数n;
第2行为图的边的条数m;
第3行至第n+2行是n个顶点的数据;
第n+3行至第n+m+2行是m条边的数据;
第三行为一个顶点徐州的数据
预期输出:
无向网
8个顶点:
北京 天津 郑州 徐州 武汉 上海 株洲 南昌
9条弧(边):
北京→郑州 :695 北京→天津 :137
天津→徐州 :674 天津→北京 :137
郑州→武汉 :534 郑州→徐州 :349 郑州→北京 :695
徐州→上海 :651 徐州→郑州 :349 徐州→天津 :674
武汉→株洲 :409 武汉→郑州 :534
上海→徐州 :651 上海→南昌 :825
株洲→南昌 :367 株洲→武汉 :409
南昌→上海 :825 南昌→株洲 :367
上海 郑州 天津
输出说明:
第一行输出图的类型。
第二行起输出图的顶点和边的数据信息。
最后一行为徐州的邻接点。
第1行为图的顶点的个数n;
第2行为图的边的条数m;
第3行至第n+2行是n个顶点的数据;
第n+3行至第n+m+2行是m条边的数据;
第三行为一个顶点徐州的数据
预期输出:
无向网
8个顶点:
北京 天津 郑州 徐州 武汉 上海 株洲 南昌
9条弧(边):
北京→郑州 :695 北京→天津 :137
天津→徐州 :674 天津→北京 :137
郑州→武汉 :534 郑州→徐州 :349 郑州→北京 :695
徐州→上海 :651 徐州→郑州 :349 徐州→天津 :674
武汉→株洲 :409 武汉→郑州 :534
上海→徐州 :651 上海→南昌 :825
株洲→南昌 :367 株洲→武汉 :409
南昌→上海 :825 南昌→株洲 :367
上海 郑州 天津
输出说明:
第一行输出图的类型。
第二行起输出图的顶点和边的数据信息。
最后一行为徐州的邻接点。
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
typedef char VertexType[20]; // 顶点类型为字符串
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,UDG,UDN}GraphKind; // {有向图,有向网,无向图,无向网}
typedef struct
{
int adjvex; // 该弧所指向的顶点的位置
int info; // 网的权值指针
}ElemType;
typedef struct ArcNode
{
ElemType data; // 除指针以外的部分都属于ElemType
struct ArcNode *nextarc; // 指向下一条弧的指针
}ArcNode; // 表结点
typedef struct
{
VertexType data; // 顶点信息
ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM]; // 头结点
typedef struct
{
AdjList vertices;
int vexnum,arcnum; // 图的当前顶点数和弧数
GraphKind kind; // 图的种类标志
}ALGraph;
#define LNode ArcNode // 定义单链表的结点类型是图的表结点的类型
#define next nextarc // 定义单链表结点的指针域是表结点指向下一条弧的指针域
typedef ArcNode *LinkList; // 定义指向单链表结点的指针是指向图的表结点的指针
int LocateElem(LinkList L,ElemType e,int (*equal)(ElemType,ElemType));
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p);
int ListInsert(LinkList &L,int i,ElemType e);// 在不带头结点的单链线性表L中第i个位置之前插入元素e
int equal(ElemType a,ElemType b);
void visit(VertexType i);
void CreateGraphF(ALGraph &G); // 采用邻接表存储结构,由文件构造没有相关信息图或网G
void Display(ALGraph G); // 输出图的邻接表G
int LocateVex(ALGraph G,VertexType u); //若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
int FirstAdjVex(ALGraph G,VertexType v); // 返回v的第一个邻接顶点的序号;否则返回-1
int NextAdjVex(ALGraph G,VertexType v,VertexType w);//v是图G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号
int main()
{
ALGraph g;
VertexType v1,v2;
int k;
CreateGraphF(g); // 利用数据文件创建图
Display(g); // 输出图
//printf("请输入顶点的值: ");
scanf("%s",v1);
//printf("输出图G中顶点%s的所有邻接顶点: ",v1);
k=FirstAdjVex(g,v1);
while(k!=-1)
{
strcpy(v2,g.vertices[k].data);
visit(v2);
k=NextAdjVex(g,v1,v2);
}
printf("\n");
return 0;
}
int equal(ElemType a,ElemType b)
{
if(a.adjvex==b.adjvex)
return 1;
else
return 0;
}
void visit(VertexType i)
{
printf("%s ",i);
}
int LocateElem(LinkList L,ElemType e,int (*equal)(ElemType,ElemType))
{ // 初始条件: 不带头结点的单链表L已存在,equal()是数据元素判定函数(满足为1,否则为0)
// 操作结果: 返回L中第1个与e满足关系equal()的数据元素的位序。
// 若这样的数据元素不存在,则返回值为0
int i=0;
LinkList p=L; // L是不带头结点的单链表
while(p)
{
i++;
if(equal(p->data,e)) // 找到这样的数据元素
return i;
p=p->next;
}
return 0;
}
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p)
{ //查找表L中满足条件的结点。如找到,返回指向该结点的指针,p指向该结点的前驱(若该结点是首元结点,则p=NULL)。
//如表L中无满足条件的结点,则返回NULL,p无定义。函数equal()的两形参的关键字相等,返回OK;否则返回ERROR
int i,j;
i=LocateElem(L,e,equal);
if(i) // 找到
{
if(i==1) // 是首元结点
{
p=NULL;
return L;
}
p=L;
for(j=2;j<i;j++)
p=p->next;
return p->next;
}
return NULL; // 没找到
}
int ListInsert(LinkList &L,int i,ElemType e)
{ // 在不带头结点的单链线性表L中第i个位置之前插入元素e
int j=1;
LinkList p=L,s;
if(i<1) // i值不合法
return 0;
s=(LinkList)malloc(sizeof(struct LNode)); // 生成新结点
s->data=e; // 给s的data域赋值
if(i==1) // 插在表头
{
s->next=L;
L=s; // 改变L
}
else
{ // 插在表的其余处
while(p&&j<i-1) // 寻找第i-1个结点
{
p=p->next;
j++;
}
if(!p) // i大于表长+1
return 0;
s->next=p->next;
p->next=s;
}
return 1;
}
void CreateGraphF(ALGraph &G)
{ // 采用邻接表 存储结构,由文件构造没有相关信息图或网G(用一个函数构造4种图)
/********** Begin **********/
int i,j,k,w;
VertexType va,vb;
ElemType e;
char filename[13];
FILE *graphlist;
scanf("%d",&G.kind);
scanf("%s",filename);
graphlist=fopen(filename,"r");
fscanf(graphlist,"%d",&G.vexnum);
fscanf(graphlist,"%d",&G.arcnum);
for(i=0;i<G.vexnum;++i)
{
fscanf(graphlist,"%s",G.vertices[i].data);
G.vertices[i].firstarc=NULL;
}
for(k=0;k<G.arcnum;++k)
{
if(G.kind%2)
fscanf(graphlist,"%s%s%d",va,vb,&w);
else
fscanf(graphlist,"%s%s",va,vb);
i=LocateVex(G,va);
j=LocateVex(G,vb);
e.info=0;
e.adjvex=j;
if(G.kind%2)
{
e.info = w;
}
ListInsert(G.vertices[i].firstarc,1,e);
if(G.kind>=2)
{
e.adjvex=i;
ListInsert(G.vertices[j].firstarc,1,e);
}
}
fclose(graphlist);
/********** End **********/
}
void Display(ALGraph G)
{ // 输出图的邻接表G
/********** Begin **********/
int i;
LinkList p;
switch(G.kind)
{
case DG: printf("有向图\n");break;
case DN: printf("有向网\n");break;
case UDG:printf("无向图\n");break;
case UDN:printf("无向网\n");
}
printf("%d个顶点:\n",G.vexnum);
for(i=0;i<G.vexnum;++i)
printf("%s ",G.vertices[i].data);
printf("\n%d条弧(边):\n",G.arcnum);
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
printf("%s→%s ",G.vertices[i].data,G.vertices[p->data.adjvex].data);
if(G.kind%2)
printf(":%d\t",p->data.info );
p=p->nextarc;
}
printf("\n");
}
/********** End **********/
}
int LocateVex(ALGraph G,VertexType u)
{ // 初始条件:图G存在,u和G中顶点有相同特征
// 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
/********** Begin **********/
int i;
for(i=0;i<G.vexnum;++i)
if(strcmp(u,G.vertices[i].data)==0) return i;
return -1;
/********** End **********/
}
int FirstAdjVex(ALGraph G,VertexType v)
{ // 初始条件:图G存在,v是G中某个顶点
// 操作结果:返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1
/********** Begin **********/
LinkList p;
int v1;
v1=LocateVex(G,v);
p=G.vertices[v1].firstarc;
if(p)
return p->data.adjvex;
else
return -1;
/********** End **********/
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ // 初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点
// 操作结果:返回v的(相对于w的)下一个邻接顶点的序号。若w是v的最后一个邻接点,则返回-1
/********** Begin **********/
LinkList p,p1;
ElemType e;
int v1;
v1=LocateVex(G,v);
e.adjvex=LocateVex(G,w);
p=Point(G.vertices[v1].firstarc,e,equal,p1);
if(!p||!p->next)
return -1;
else
return p->next->data.adjvex;
/********** End **********/
}
第2关:图的深度遍历
任务描述
本关任务:以邻接表存储图,要求编写程序实现图的深度优先遍历
测试说明
平台会对你编写的代码进行测试:
测试输入:
0
lt2.txt
输入说明:
第一行输入0,表示输入图的类型为有向图。
第二行输入文件名,该文件里保存了图的数据信息,内容如下:
第1行为图的顶点的个数n;
第2行为图的边的条数m;
第3行至第n+2行是n个顶点的数据;
第n+3行至第n+m+2行是m条边的数据;
预期输出:
有向图
7个顶点:
高等数学 程序设计基础 C语言 离散数学 数据结构 编译原理 操作系统
9条弧(边):
高等数学→离散数学 高等数学→C语言
程序设计基础→C语言 程序设计基础→数据结构
C语言→数据结构
离散数学→编译原理 离散数学→数据结构
数据结构→操作系统 数据结构→编译原理
深度优先遍历序列:
高等数学 离散数学 编译原理 数据结构 操作系统 C语言 程序设计基础
输出说明:
第一行输出图的类型。
第二行起输出图的顶点和边的数据信息。
最后一行为从“高等数学”出发进行深度优先遍历的序列。
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include"ALGraph.h"
void DFS(ALGraph G,int v); //从第v个顶点出发递归地深度优先遍历图G
void DFSTraverse(ALGraph G); // 对图G作深度优先遍历
int visited[MAX_VERTEX_NUM]; // 访问标志数组(全局量)
int main()
{
ALGraph g;
CreateGraphF (g); // 利用数据文件创建图
Display(g); // 输出图
printf("深度优先遍历序列:\n");
DFSTraverse(g);
return 0;
}
void DFS(ALGraph G,int v)
{ //从第v个顶点出发递归地深度优先遍历图G
/********** Begin **********/
ArcNode *p;
p=G.vertices[v].firstarc;
visited[v]=1;
visit(G.vertices[v].data);
for(int w=FirstAdjVex(G,G.vertices[v].data);w>=0;w=NextAdjVex(G,G.vertices[v].data,G.vertices[w].data)){
if(!visited[w])
DFS(G,w);
}
/********** End **********/
}
void DFSTraverse(ALGraph G)
{ // 对图G作深度优先遍历
/********** Begin **********/
int v;
for(v=0;v<G.vexnum;v++)
visited[v]=0;
for(v=0;v<G.vexnum;v++)
if(!visited[v])
DFS(G,v);
printf("\n");
/********** End **********/
}
第3关:图的广度遍历
任务描述
本关任务:以邻接表存储图,要求编写程序实现图的广度优先遍历。
测试说明
平台会对你编写的代码进行测试:
测试输入:
0
lt2.txt
输入说明:
第一行输入0,表示输入图的类型为有向图。
第二行输入文件名,该文件里保存了图的数据信息,内容如下:
第1行为图的顶点的个数n;
第2行为图的边的条数m;
第3行至第n+2行是n个顶点的数据;
第n+3行至第n+m+2行是m条边的数据;
预期输出:
有向图
7个顶点:
高等数学 程序设计基础 C语言 离散数学 数据结构 编译原理 操作系统
9条弧(边):
高等数学→离散数学 高等数学→C语言
程序设计基础→C语言 程序设计基础→数据结构
C语言→数据结构
离散数学→编译原理 离散数学→数据结构
数据结构→操作系统 数据结构→编译原理
广度优先遍历序列:
高等数学 离散数学 C语言 编译原理 数据结构 操作系统 程序设计基础
输出说明:
第一行输出图的类型。
第二行起输出图的顶点和边的数据信息。
最后一行为从“高等数学”出发进行广度优先遍历的序列。
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include"ALGraph.h"
#include"sqqueue.h"
void BFSTraverse(ALGraph G); //按广度优先非递归遍历图G
int visited[MAX_VERTEX_NUM]; // 访问标志数组(全局量)
int main()
{
ALGraph g;
CreateGraphF (g); // 利用数据文件创建图
Display(g); // 输出图
printf("广度优先遍历序列:\n");
BFSTraverse(g);
return 0;
}
void BFSTraverse(ALGraph G)
{ //按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。
/********** Begin **********/
int v,u,w;
ArcNode *p;
SqQueue Q;
for(v=0;v<G.vexnum;v++)
visited[v]=0;
InitQueue(Q);
for(v=0;v<G.vexnum;v++)
if(!visited[v]){
visited[v]=1;
visit(G.vertices[v].data);
EnQueue(Q,v);
while(!QueueEmpty(Q)){
DeQueue(Q,u);
p=G.vertices[u].firstarc;
while(p){
w=p->data.adjvex;
if(!visited[w]){
visited[w]=1;
visit(G.vertices[w].data);
EnQueue(Q,w);
}
p=p->nextarc;
}
}
}
printf("\n");
/********** End **********/
}
辅助文件
lt.txt
8
9
北京
天津
郑州
徐州
武汉
上海
株洲
南昌
北京 天津 137
北京 郑州 695
天津 徐州 674
郑州 徐州 349
郑州 武汉 534
武汉 株洲 409
株洲 南昌 367
南昌 上海 825
徐州 上海 651
lt2.cpp
7
9
高等数学
程序设计基础
C语言
离散数学
数据结构
编译原理
操作系统
高等数学 C语言
高等数学 离散数学
程序设计基础 数据结构
程序设计基础 C语言
C语言 数据结构
离散数学 数据结构
离散数学 编译原理
数据结构 编译原理
数据结构 操作系统
ALGraph.h
#ifndef __ALGraph_H__
#define __ALGraph_H__
typedef char VertexType[20]; // 顶点类型为字符串
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,UDG,UDN}GraphKind; // {有向图,有向网,无向图,无向网}
typedef struct
{
int adjvex; // 该弧所指向的顶点的位置
int info; // 网的权值指针
}ElemType;
typedef struct ArcNode
{
ElemType data; // 除指针以外的部分都属于ElemType
struct ArcNode *nextarc; // 指向下一条弧的指针
}ArcNode; // 表结点
typedef struct
{
VertexType data; // 顶点信息
ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM]; // 头结点
typedef struct
{
AdjList vertices;
int vexnum,arcnum; // 图的当前顶点数和弧数
GraphKind kind; // 图的种类标志
}ALGraph;
#define LNode ArcNode // 定义单链表的结点类型是图的表结点的类型
#define next nextarc // 定义单链表结点的指针域是表结点指向下一条弧的指针域
typedef ArcNode *LinkList; // 定义指向单链表结点的指针是指向图的表结点的指针
int equal(ElemType a,ElemType b);
void visit(VertexType i);
int LocateVex(ALGraph G,VertexType u);//若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
int FirstAdjVex(ALGraph G,VertexType v); // 返回v的第一个邻接顶点的序号;否则返回-1
int NextAdjVex(ALGraph G,VertexType v,VertexType w);//v是图G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号
void CreateGraphF(ALGraph &G);// 采用邻接表存储结构,由文件构造没有相关信息图或网G
void Display(ALGraph G); // 输出图的邻接表G
#endif
ALGraph.cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"ALGraph.h"
#include"LinkList.h"
int LocateVex(ALGraph G,VertexType u)
{ // 初始条件:图G存在,u和G中顶点有相同特征
// 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
int i;
for(i=0;i<G.vexnum;++i)
if(strcmp(u,G.vertices[i].data)==0)
return i;
return -1;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ // 初始条件:图G存在,v是G中某个顶点
// 操作结果:返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1
LinkList p;
int v1;
v1=LocateVex(G,v); // v1为顶点v在图G中的序号
p=G.vertices[v1].firstarc;
if(p)
return p->data.adjvex;
else
return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ // 初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点
// 操作结果:返回v的(相对于w的)下一个邻接顶点的序号。若w是v的最后一个邻接点,则返回-1
LinkList p,p1; // p1在Point()中用作辅助指针
ElemType e;
int v1;
v1=LocateVex(G,v); // v1为顶点v在图G中的序号
e.adjvex=LocateVex(G,w); // e.adjvex为顶点w在图G中的序号
p=Point(G.vertices[v1].firstarc,e,equal,p1); // p指向顶点v的链表中邻接顶点为w的结点
if(!p||!p->next) // 没找到w或w是最后一个邻接点
return -1;
else // p->data.adjvex==w
return p->next->data.adjvex; // 返回v的(相对于w的)下一个邻接顶点的序号
}
void CreateGraphF(ALGraph &G)
{ // 采用邻接表 存储结构,由文件构造没有相关信息图或网G(用一个函数构造4种图)
int i,j,k,w; // w是权值
VertexType va,vb; // 连接边或弧的2顶点
ElemType e;
char filename[13];
FILE *graphlist;
//printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d",&G.kind);
//printf("请输入数据文件名:");
scanf("%s",filename);
graphlist=fopen(filename,"r"); // 以读的方式打开数据文件,并以graphlist表示
fscanf(graphlist,"%d",&G.vexnum);
fscanf(graphlist,"%d",&G.arcnum);
for(i=0;i<G.vexnum;++i) // 构造顶点向量
{
fscanf(graphlist,"%s",G.vertices[i].data);
G.vertices[i].firstarc=NULL; // 初始化与该顶点有关的出弧链表
}
for(k=0;k<G.arcnum;++k) // 构造相关弧链表
{
if(G.kind%2) // 网
fscanf(graphlist,"%s%s%d",va,vb,&w);
else // 图
fscanf(graphlist,"%s%s",va,vb);
i=LocateVex(G,va); // 弧尾
j=LocateVex(G,vb); // 弧头
e.info=0; // 给待插表结点e赋值,图无权
e.adjvex=j; // 弧头
if(G.kind%2) // 网
{
e.info = w;
}
ListInsert(G.vertices[i].firstarc,1,e); // 插在第i个元素(出弧)的表头
if(G.kind>=2) // 无向图或网,产生第2个表结点,并插在第j个元素(入弧)的表头
{
e.adjvex=i; // e.info不变,不必再赋值
ListInsert(G.vertices[j].firstarc,1,e); // 插在第j个元素的表头
}
}
fclose(graphlist); // 关闭数据文件
}
void Display(ALGraph G)
{ // 输出图的邻接表G
int i;
LinkList p;
switch(G.kind)
{
case DG: printf("有向图\n"); break;
case DN: printf("有向网\n"); break;
case UDG:printf("无向图\n"); break;
case UDN:printf("无向网\n");
}
printf("%d个顶点:\n",G.vexnum);
for(i=0;i<G.vexnum;++i)
printf("%s ",G.vertices[i].data);
printf("\n%d条弧(边):\n",G.arcnum);
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
printf("%s→%s ",G.vertices[i].data,G.vertices[p->data.adjvex].data);
if(G.kind%2) // 网
printf(":%d\t",p->data.info );
p=p->nextarc;
}
printf("\n");
}
}
int equal(ElemType a,ElemType b)
{
if(a.adjvex==b.adjvex)
return 1;
else
return 0;
}
void visit(VertexType i)
{
printf("%s ",i);
}
LinkList.h
#ifndef __LinkList_H__
#define __LinkList_H__ // 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#include"ALGraph.h"
typedef LNode * LinkList; // 另一种定义LinkList的方法
// 不带头结点的单链表的部分基本操作(9个)
#define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
void InitList(LinkList &L);
void ClearList(LinkList &L);
int ListEmpty(LinkList L);
int ListLength(LinkList L);
int GetElem(LinkList L,int i,ElemType &e);
int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType));
int ListInsert(LinkList &L,int i,ElemType e);
int ListDelete(LinkList &L,int i,ElemType &e);
void ListTraverse(LinkList L,void(*vi)(ElemType));
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p);//查找表L中满足条件的结点。如找到
#endif
LinkList.cpp
#include<stdio.h>
#include<stdlib.h>
#include"LinkList.h"
// 不带头结点的单链表的部分基本操作(9个)
void InitList(LinkList &L)
{ // 操作结果:构造一个空的线性表L
L=NULL; // 指针为空
}
#define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
void ClearList(LinkList &L)
{ // 初始条件:线性表L已存在。操作结果:将L重置为空表
LinkList p;
while(L) // L不空
{
p=L; // p指向首元结点
L=L->next; // L指向第2个结点(新首元结点)
free(p); // 释放首元结点
}
}
int ListEmpty(LinkList L)
{ // 初始条件:单链表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
if(L)
return FALSE;
else
return TRUE;
}
int ListLength(LinkList L)
{ // 初始条件:线性表L已存在。操作结果:返回L中数据元素个数
int i=0;
LinkList p=L;
while(p) // p指向结点(没到表尾)
{
p=p->next; // p指向下一个结点
i++;
}
return i;
}
int GetElem(LinkList L,int i,ElemType &e)
{ // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
int j=1;
LinkList p=L;
if(i<1) // i值不合法
return ERROR;
while(j<i&&p) // 没到第i个元素,也没到表尾
{
j++;
p=p->next;
}
if(j==i) // 存在第i个元素
{
e=p->data;
return OK;
}
else
return ERROR;
}
int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
{ // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
// 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
// 若这样的数据元素不存在,则返回值为0
int i=0;
LinkList p=L;
while(p)
{
i++;
if(compare(p->data,e)) // 找到这样的数据元素
return i;
p=p->next;
}
return 0;
}
int ListInsert(LinkList &L,int i,ElemType e)
{ // 在不带头结点的单链线性表L中第i个位置之前插入元素e
int j=1;
LinkList p=L,s;
if(i<1) // i值不合法
return ERROR;
s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
s->data=e; // 给s的data域赋值
if(i==1) // 插在表头
{
s->next=L;
L=s; // 改变L
}
else
{ // 插在表的其余处
while(p&&j<i-1) // 寻找第i-1个结点
{
p=p->next;
j++;
}
if(!p) // i大于表长+1
return ERROR;
s->next=p->next;
p->next=s;
}
return OK;
}
int ListDelete(LinkList &L,int i,ElemType &e)
{ // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值
int j=1;
LinkList p=L,q;
if(i==1) // 删除第1个结点
{
L=p->next; // L由第2个结点开始
e=p->data;
free(p); // 删除并释放第1个结点
}
else
{
while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
{
p=p->next;
j++;
}
if(!p->next||j>i-1) // 删除位置不合理
return ERROR;
q=p->next; // 删除并释放结点
p->next=q->next;
e=q->data;
free(q);
}
return OK;
}
void ListTraverse(LinkList L,void(*vi)(ElemType))
{ // 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi()
LinkList p=L;
while(p)
{
vi(p->data);
p=p->next;
}
printf("\n");
}
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p)
{ //查找表L中满足条件的结点。如找到,返回指向该结点的指针,p指向该结点的前驱(若该结点是首元结点,则p=NULL)。
//如表L中无满足条件的结点,则返回NULL,p无定义。函数equal()的两形参的关键字相等,返回OK;否则返回ERROR
int i,j;
i=LocateElem(L,e,equal);
if(i) // 找到
{
if(i==1) // 是首元结点
{
p=NULL;
return L;
}
p=L;
for(j=2;j<i;j++)
p=p->next;
return p->next;
}
return NULL; // 没找到
}
sqqueue.h
#ifndef __SQQUEUE_H__
#define __SQQUEUE_H__
#include"symbol.h"
#define MAX_QSIZE 20 // 最大队列长度+1
typedef int VRType; // 顶点关系类型
typedef VRType QElemType;
struct SqQueue
{
QElemType *base; // 初始化的动态分配存储空间
int front; // 头指针,若队列不空,指向队列头元素
int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
};
void InitQueue(SqQueue &Q); // 构造一个空循环队列Q
void DestroyQueue(SqQueue &Q); // 销毁循环队列Q,Q不再存在
void ClearQueue(SqQueue &Q); // 将Q清为空循环队列
int QueueEmpty(SqQueue Q); // 若循环队列Q为空队列,则返回TRUE;否则返回FALSE
int QueueLength(SqQueue Q); // 返回Q的元素个数,即循环队列的长度
int GetHead(SqQueue Q,QElemType &e); // 若循环队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
int EnQueue(SqQueue &Q,QElemType e); // 插入元素e为循环队列Q的新的队尾元素
int DeQueue(SqQueue &Q,QElemType &e); // 若循环队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR
void QueueTraverse(SqQueue Q,void(*vi)(QElemType)); // 从队头到队尾依次对队列Q中每个元素调用函数vi()
#endif
sqqueue.cpp
#include<stdio.h>
#include<stdlib.h>
#include"sqqueue.h"
typedef int QElemType;
void InitQueue(SqQueue &Q)
{
Q.base=(QElemType *)malloc(MAX_QSIZE*sizeof(QElemType));
if(!Q.base) // 存储分配失败
exit(OVERFLOW);
Q.front=Q.rear=0;
}
// 销毁循环队列Q,Q不再存在
void DestroyQueue(SqQueue &Q)
{
if(Q.base)
free(Q.base);
Q.base=NULL;
Q.front=Q.rear=0;
}
// 将Q清为空循环队列
void ClearQueue(SqQueue &Q)
{
Q.front=Q.rear=0;
}
// 若循环队列Q为空队列,则返回TRUE;否则返回FALSE
int QueueEmpty(SqQueue Q)
{
if(Q.front==Q.rear) // 队列空的标志
return TRUE;
else
return FALSE;
}
// 返回Q的元素个数,即循环队列的长度
int QueueLength(SqQueue Q)
{
return(Q.rear-Q.front+MAX_QSIZE)%MAX_QSIZE;
}
// 若循环队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
int GetHead(SqQueue Q,QElemType &e)
{
if(Q.front==Q.rear) // 队列空
return ERROR;
e=Q.base[Q.front];
return OK;
}
// 插入元素e为循环队列Q的新的队尾元素
int EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAX_QSIZE==Q.front) // 队列满
return ERROR;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAX_QSIZE;
return OK;
}
// 若循环队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR
int DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.front==Q.rear) // 队列空
return ERROR;
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAX_QSIZE;
return OK;
}
// 从队头到队尾依次对队列Q中每个元素调用函数vi()
void QueueTraverse(SqQueue Q,void(*vi)(QElemType))
{
int i;
i=Q.front;
while(i!=Q.rear)
{
vi(Q.base[i]);
i=(i+1)%MAX_QSIZE;
}
printf("\n");
}
symbol.h
#ifndef __SYMBOL_H__
#define __SYMBOL_H__
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#endif