图的邻接表存储及遍历操作

第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
  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
邻接表递归遍历实现DFS的过程如下: 1. 首先,我们需要定义一个访问标志数组visited,用于标记顶点是否已经被访问过。初始化visited数组为0,表示所有顶点都未被访问。 2. 接下来,我们定义一个DFS函数,该函数接受两个参数:g和要遍历的起始顶点i。 3. 在DFS函数中,首先访问并输出顶点i的数据,然后将visited[i]标记为1,表示该顶点已经被访问。 4. 接着,我们通过访问顶点i的邻接链表,遍历所有与顶点i相邻的顶点。 5. 对于每个未被访问过的邻接顶点j,我们递归调用DFS函数,将j作为起始顶点,以便继续深度遍历。 6. 最后,我们通过遍历中的所有顶点,保证非连通遍历,对于每个未被访问过的顶点v,我们调用DFS函数进行深度优先遍历。 下面是具体的代码实现: ```c void DFS(graph g, int i) { ArcNode *p; printf("<%d>", g.adjlist[i].data); // 访问第i个顶点 visited[i = 1; // 标记顶点i已经被访问 p = g.adjlist[i].firstedge; // 获取顶点i的第一个邻接点 while (p != NULL) { if (visited[p->adjvex == 0) DFS(g, p->adjvex); // 对未访问的邻接顶点进行递归调用DFS p = p->next; } } void DFSTraverse(graph g) { int v; for (v = 0; v < g.vex; v++) visited[v = 0; // 初始化标志数组 for (v = 0; v < g.vex; v++) { if (!visited[v]) DFS(g, v); // 从第v个顶点出发递归地深度优先遍历g } } ``` 以上就是使用邻接表实现DFS深度优先搜索的过程。首先定义了DFS函数,在该函数中访问并输出顶点数据,并通过递归调用DFS函数,对未访问的邻接顶点进行深度优先遍历。然后定义了DFSTraverse函数,用于遍历中的所有顶点,保证非连通遍历

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杼蛘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值