代码参照了严蔚敏、吴伟民编写的数据结构(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