C语言 数据结构 图的邻接表存储 基本操作(附输入样例和讲解)

代码参照了严蔚敏、吴伟民编写的数据结构(C语言版)。

所有代码采用C语言编写。讲解请查看注释。

头文件及宏定义

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_VERTEX_NUM 20//最大顶点个数

#define OK 1
#define Fail 0 
#define False 0
#define True 1
#define Error 0;

typedef定义数据类型和结构体

typedef enum{DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网} 
typedef int Status;
typedef char InfoType;
typedef char VertexType;

typedef struct ArcNode{//表结点 
	int adjvex;//该弧所指向的顶点的位置 
	struct ArcNode *nextarc;//指向下一条弧的指针 
	InfoType *info;//该弧相关信息的指针 
}ArcNode; 

typedef struct VNode{//头结点 
	VertexType data;//顶点信息 
	ArcNode *firstarc;//指向第一条依附该顶点的弧的指针 
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct{
	AdjList vertices;//存储顶点的数组 
	int vexnum,arcnum;//图的顶点数和弧数 
	int kind;//图的种类标志 
}ALGraph;

LocateVex

Status LocateVex(ALGraph G, VertexType u){//找出顶点u在顶点数组vertices中的次序 
	int i=0; 
	for (i=0; i<G.vexnum; i++){
		if (G.vertices[i].data==u)
			return i;
	}
	return False;//未匹配到 
}

CreateGraph

Status CreateGraph(ALGraph *G){//构造有向无权图
	G->kind=DG;//有向图 
	int i=0,j=0,k=0;
	printf("请输入图的顶点个数和弧数\n");
	fflush(stdin);
	scanf("%d",&G->vexnum);
	fflush(stdin);
	scanf("%d",&G->arcnum);
	
	printf("请输入所有顶点\n");
	for(i=0;i<G->vexnum;i++){
	    fflush(stdin);//清空输入缓存区,否则会将上次输入结束后的回车符当成一个字符存入。下面同理 
	    scanf("%c",&G->vertices[i].data);//将所有的顶点读入数组vexs中进行存储 
	    G->vertices[i].firstarc=NULL;//所有头结点的弧指针域为空 
	}
	char v1=0,v2=0;
	printf("请输入弧尾和弧头,弧尾指向弧头\n");
	for(k=0;k<G->arcnum;k++){//对矩阵进行赋值 

	    fflush(stdin);
		scanf("%c%c",&v1,&v2);
		i=LocateVex(*G,v1);//弧尾 
		j=LocateVex(*G,v2);//弧头 
		
		//头插法,将新建的弧尾的表结点链接到弧头的头结点后 
		ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));//给弧头分配空间 
		p->adjvex=j;
		p->nextarc=G->vertices[i].firstarc;
		G->vertices[i].firstarc=p;
	}
	return OK;
}

Display

void Display(ALGraph G){//打印链表 
	int i=0;
	ArcNode *p=NULL;
	for(i=0;i<G.vexnum;i++){
		printf("顶点%c:",G.vertices[i].data);
		p=G.vertices[i].firstarc;//取头结点的指针 
		while(p){
			char vex=G.vertices[p->adjvex].data;//遍历头结点后的每一个弧结点,找出弧结点指向的顶点 
			printf("->%c",vex);
			p=p->nextarc;//取到下一个弧结点 
		} 
		printf("\n");
	}
}

Destory

Status DestoryGraph(ALGraph *G){//销毁图 
	int i=0;
	ArcNode *p=NULL,*q=NULL;
	for(i=0;i<G->vexnum;i++){
		p=G->vertices[i].firstarc;
		while(p){
			q=p->nextarc;
			free(p);
			p=q;//下次循环开始前会判断下一个弧结点是否存在 
		}
	}
	for(i;i<G->vexnum;i++){
		G->vertices[i].data=0;
		G->vertices[i].firstarc=NULL;
	} 
	G->arcnum=0;
	G->vexnum=0;
}

GetVex

Status GetVex(ALGraph G,VertexType v){//返回图中顶点的值
	int i=0;
	for(i=0;i<G.vexnum;i++){
		if(v==G.vertices[i].data) return i;
	}
	return False;
}

PutVex

Status PutVex(ALGraph *G,VertexType  v,VertexType  value){//将图中的顶点v改为顶点value 
	int i=0;
	for(i=0;i<G->vexnum;i++){
		if(v==G->vertices[i].data) {
			G->vertices[i].data=value;
			return OK;
		}
	}
	return False;
}

FirstAdjVex

Status FirstAdjVex(ALGraph G,VertexType  v){//找出v的下一个邻接顶点 
	int i=0;
	i=LocateVex(G,v);
	ArcNode *p=NULL;
	p=G.vertices[i].firstarc;//找到以v为头结点的第一个弧结点
	if(p) 	return p->adjvex;//若该节点存在,则返回这个弧结点指向的顶点的值
	return Fail;
}

NextAdjVex

Status NextAdjVex(ALGraph G,VertexType v,VertexType w){//找出v相对于w的下一个邻接顶点 
	int i=0,j=0;
	i=LocateVex(G,v);
	j=LocateVex(G,w);
	ArcNode *p=NULL;
	p=G.vertices[i].firstarc;
	while(p){
		if(p->adjvex==j) return p->nextarc->adjvex;//如果以v为头结点的第一个弧结点,则返回下一个弧结点指向的顶点的值
		p=p->nextarc;//否则继续遍历下一个弧结点 
	}
	return Fail;
}

InsertVex

Status InsertVex(ALGraph *G,VertexType v){//插入顶点v 
	G->vexnum++;
	G->vertices[G->vexnum-1].data=v;//增加新顶点代表的头结点 
	G->vertices[G->vexnum-1].firstarc=NULL;
	return OK; 
}

DeleteVex

Status DeleteVex(ALGraph *G,VertexType v){//删除顶点v 
	int count=0;//统计删除了几条弧 
	int i=0,j=0,temp=0;
	ArcNode *p=NULL,*q=NULL;
	j=LocateVex(*G,v);
	temp=j;
	for(temp;temp<G->vexnum;temp++){
		G->vertices[temp].data=G->vertices[temp+1].data;//存储顶点的数组中向前移一位,覆盖要删除的顶点
		G->vertices[temp].firstarc=G->vertices[temp+1].firstarc;
	}
	G->vexnum--;

	for(i=0;i<G->vexnum;i++){
		p=G->vertices[i].firstarc;
		while(p){
			if(p->adjvex>j){//顶点位于要删除顶点的后方,数组减少一个元素后相对位置需要变化 
				p->adjvex--;
				p=p->nextarc;
			}
			else if(p->adjvex==j){//顶点就是需要删除的顶点 
				if(p==G->vertices[i].firstarc) //p所指是第1条弧
				//这里一定要进行一次判断,否则会误删除掉原本位于已删除结点v后面的头结点,并在打印输出的时候中断 
				G->vertices[i].firstarc=p->nextarc;//不删除,指向下一条弧
                else{//删除弧 
                    q=p;
				    p=p->nextarc;
				    free(p);
				    count++;
				}
			}
			else    p=p->nextarc;
		}
	}
	G->arcnum=G->arcnum-count; 
	return OK; 
}

InsertArc

Status InsertArc(ALGraph *G,VertexType v,VertexType w){//增加顶点v指向顶点w的弧
	int i=LocateVex(*G,v);
	int j=LocateVex(*G,w);
	ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));//给弧头分配空间 
		p->adjvex=j;
		p->nextarc=G->vertices[i].firstarc;
		G->vertices[i].firstarc=p;
		return OK;
}

DeleteArc

Status DeleteArc(ALGraph *G,VertexType v,VertexType w){//删除顶点v和w之间的弧
	int i=LocateVex(*G,v);
	int j=LocateVex(*G,w);
	ArcNode *p=G->vertices[i].firstarc;
	ArcNode *q=NULL; 
	while(p){
		if(p->adjvex==j){
			if(p==G->vertices[i].firstarc) 
				G->vertices[i].firstarc=p->nextarc;
			else{
				q=p;
			    p=p->nextarc;
			    free(q);
			}
		}
	else	p=p->nextarc;
	}
	return OK;
}

定义全局变量

int visited[MAX_VERTEX_NUM];//在DFS和BFS中用到

DFS

void DFS(ALGraph G,int n){//从第n个顶点出发深度优先遍历图G 
	int i;
    printf("%c", G.vertices[n].data);//访问顶点 
    visited[n]=True;//置标志数组为真,表示已访问过 
    ArcNode* p=NULL;
    p=G.vertices[n].firstarc;
    while(p){//从该顶点的头结点开始依次访问弧结点 
    	if(visited[p->adjvex]==False)    DFS(G,p->adjvex);//若未访问过,则访问 
    	p=p->nextarc;
	}
}

DFSTraverse

void DFSTraverse(ALGraph G){//对图G进行深度优先遍历
	int i=0,n=0;
	for(i=0;i<G.vexnum;i++) visited[i]=False; //初始化标志数组 
	for(n=0;n<G.vexnum;n++){//因为图可能是非联通图,递归访问下一个顶点时可能会中断,因此需要从每一个顶点开始做深度优先遍历
		if(visited[n]==False)//判断是否被访问过,未被访问过时访问 
		DFS(G,n);
	}
} 

BFS

void BFS(ALGraph G,int n){//从第n个顶点出发广度优先遍历图G
	int que[MAX_VERTEX_NUM],front=0,rear=0;
	ArcNode* p=NULL;
	int i=0; 
	printf("%c", G.vertices[n].data);//访问顶点
	visited[n]=True;//置标志数组为真,表示已访问过 
	rear=(rear+1)%MAX_VERTEX_NUM;//入队 
	que[rear]=n;
	while(front!=rear){//队列不空时 
		front=(front+1)%MAX_VERTEX_NUM;//出队 
		i=que[front];
		p=G.vertices[i].firstarc;
		while(p){
			if(visited[p->adjvex]==False){//若未访问过 
				printf("%c", G.vertices[p->adjvex].data);//访问顶点
				visited[p->adjvex]=True;//置标志数组为真,表示已访问过 
				rear=(rear+1)%MAX_VERTEX_NUM;//入队 
            	que[rear]=p->adjvex;
			}
			p=p->nextarc;
		}
	}
}

BFSTraverse

void BFSTraverse(ALGraph G){//对图G进行广度优先遍历
	int i=0,n=0;
	for(i=0;i<G.vexnum;i++) visited[i]=False; //初始化标志数组 
	for(n=0;n<G.vexnum;n++){//因为图可能是非联通图,递归访问下一个顶点时可能会中断,因此需要从每一个顶点开始做深度优先遍历
		if(visited[n]==False)//判断是否被访问过,未被访问过时访问 
		BFS(G,n);
	}
}

输入样例

很多函数被我注释掉了,需要使用的话自行取消注释。

int main(void){
	ALGraph G;
	CreateGraph(&G);
	//DestoryGraph(&G);
	//GetVex(G,'e');
	//InsertVex(&G,'f');
	//DeleteVex(&G,'c');
	//InsertArc(&G,'d','e');
	//DeleteArc(&G,'a','d');
	Display(G);
	//FirstAdjVex(G,'b');
	//NextAdjVex(G,'b','e');
	printf("深度优先遍历\n");
	DFSTraverse(G);
	printf("\n广度优先遍历\n");
	BFSTraverse(G);
} 

输入:

5
6
a
b
c
d
e
ab
ad
bc
be
cd
ce

有向无权图

输出结果

输出结果

  • 13
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值