邻接多重链表的实现

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2

#define MAX_VERTEX_NUM 20

//顶点数据类型
typedef int VertexType;

typedef int Status;

typedef enum {unvisited,isvisited}VisitIf;//枚举类型,判断是否被访问  0 代表没有被访问 1 代表访问过了

//图的种类:无向图/网
typedef enum {UDG,UDN}GraphKind;

typedef struct EBox {
    VisitIf mark;   //访问标记
    int ivex;   //边顶点一
    int jvex;   //边顶点二
    struct EBox *ilink; //指向依附于顶点一的下一条边,类似于起点相同的一条弧
    struct EBox *jlink; //指向依附于顶点二的下一条边,类似与终点想同的一条弧
    int weight; //边的权值
}EBox;


typedef struct VexBox {
    VertexType data;//数据域
    EBox *firstarc; //指向第一条依附于该顶点的边
}VexBox;


typedef struct {
    VexBox adjmulist[MAX_VERTEX_NUM];//顶点数组
    int vexnum; //图的顶点数
    int arcnum; //图的边数
    GraphKind kind; //图的种类
}AMLGraph;


//访问标志数组
int visited[MAX_VERTEX_NUM];


//创建图
Status CreateGraph(AMLGraph *G);

//定位一个顶点值为图中的位置,否则返回-1
int LocateVex(AMLGraph G,VertexType v);


//返回顶点的值
VertexType GetVex(AMLGraph G,int v);

//赋值
Status PutVex(AMLGraph *G,VertexType v,VertexType value ); 

//插入一个顶点
Status InsertVex(AMLGraph *G,VertexType v);

//插入一段弧
Status InsertArc(AMLGraph *G,VertexType v,VertexType w);

//返回顶点值为v的下一个邻接顶点的序号,否怎返回-1
int FirstAdjVex(AMLGraph G,VertexType v);

//返回顶点值为v相对于顶点值为w的下一个顶点的序号
int NextAdjVex(AMLGraph G,VertexType v,VertexType w);


//深度优先遍历
Status DFSTraverse(AMLGraph G);


//递归实现深度遍历邻接点
void DFS(AMLGraph G,int i);


这是"amlgraph.h"的头文件

#include <stdio.h>
#include <stdlib.h>
#include "amlgraph.h"


/*
* @description:创建图(无向图/网)
*/
Status CreateGraph(AMLGraph *G) {
	int i,j,k,w;
	VertexType va,vb;
	EBox *p;
	
	//确定图的种类
	printf("please enter the kind of graph:");
	//输入0  代表无相图 输入1 代表网 就是有权值  是根据枚举来的
	scanf("%d",&(*G).kind);//这是c语言的标记方式 &是取地址符号

	//确定图的顶点和边数
	printf("please enter vexnum and arcnum:");
	//依次输入图中的点点数  vexnum  边数  arcnum  记得用逗号隔开
	scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);


	//确定图的各个顶点
	printf("please enter each value of graph:");
	for(i = 0; i < (*G).vexnum ; i++)  {
		//输入链表中顶点的信息  输入数据
		scanf("%d,",&(*G).adjmulist[i].data);
		//一开始的时候 将firstarc指向空
		(*G).adjmulist[i].firstarc = NULL;
	}
	
	//确定各个顶点间关系,即建立边
	if((*G).kind == UDG)
		//如果是无向图 只要输入头尾结点即可
		printf("please enter heads and tails:\n");
	else 
		//如果是网  那么就要输入头结点 尾结点 以及权重
		printf("please enter heads,weights and tails\n");
	//接下来是具体的输入过程 ,记得中间要用逗号隔开数据
	for(k = 0; k < (*G).arcnum ;k++) {
		if((*G).kind == UDG)
			scanf("%d,%d",&va,&vb);
		else 
			scanf("%d,%d",&va,&vb,&w);
		//放回两顶点在顶点向量数组中位置
		//将这两个顶点在顶点向量数组中的位置传出来
		i = LocateVex(*G,va);
		j = LocateVex(*G,vb);
		

		if(i < 0 || j < 0)
			return ERROR;

                //为变表分配空间
		p = (EBox *) malloc(sizeof(struct EBox));
		if(!p)
			exit(OVERFLOW);

		///建立新节点  在边表中将头尾结点的信息填上
		p->ivex = i;
		p->jvex = j;
		p->mark = unvisited;//设置这条边为未访问
		//注意每次插入新节点都是在链表的表头进行
		//插入的时候采用的都是头插法
		//这里是将p->ilink指向原来firstarc指向的位置
		//再将firstarc指向这条边
		p->ilink = (*G).adjmulist[i].firstarc;
		p->jlink = (*G).adjmulist[j].firstarc;
		(*G).adjmulist[i].firstarc = p;
		(*G).adjmulist[j].firstarc = p;
		if((*G).kind == UDN)
			//如果是网图还需要输入权值
			p->weight = w;
	}

	return OK;
}



/*
* @description:定位一个顶点值在图中的位置,无则返回-1
*/
//返回该顶点在顶点数组中的下标位置
int LocateVex(AMLGraph G,VertexType v) {
	int i;

	for(i = 0; i < G.vexnum ; i++)
		if(G.adjmulist[i].data == v)
			return i;

	return -1;
}


/*
* @description:返回顶点v的值
*/
//这里是给定一个位置,返回顶点数组中该位置的信息
VertexType GetVex(AMLGraph G,int v) {
	if(v > G.vexnum || v < 0)
		exit(ERROR);
	
	return G.adjmulist[v].data;
}


/*
* @description:对顶点值为v的顶点赋值为value
*/
//就是替换顶点的数据域
Status PutVex(AMLGraph *G,VertexType v,VertexType value) {
	int i;
	//先返回该顶点在顶点的数组中的位置
	i = LocateVex(*G,v);

	if(i < 0)
		return ERROR;
	//再讲这个顶点的数据域改为value
	(*G).adjmulist[i].data = value;

	return OK;
}


/*
* @description:返回顶点值为v的下一个邻接点的序号,否则返回-1
*/
int FirstAdjVex(AMLGraph G,VertexType v) {
	int i;
	EBox *p;
	//先找到这个顶点在顶点数组中的位置
	i = LocateVex(G,v);

	if(i < 0)
		return -1;
	//指针p指向这个顶点的第一个邻接边
	p = G.adjmulist[i].firstarc;

	if(p)
		//如果这个边的尾顶点与输入顶点在顶点数中的位置相等
		if(p->ivex == i)
			return p->jvex; //返回这个边的头结点
		//要注意这种情况的理解
		else
			//这里是出度与入度的关系
			return p->ivex;

	else 
		return -1;

}


/*
* @description:返回顶点值为v相对于顶点值为w的下一个邻接顶点的序号
*/
int NextAdjVex(AMLGraph G,VertexType v,VertexType w) {
	int i,j;
	EBox *p;
	//先找到这两个顶点在顶点数组中的位置
	i = LocateVex(G,v);
	j = LocateVex(G,w);

	p = G.adjmulist[i].firstarc;	//不管怎样先找到入口
	
	while(p)
		//其实这两句话的意思就是  这条边不是以v w位顶点的边
		if(p->ivex == i && p->jvex != j ) //情况1 所谓的情况一  就是这条边是以v为起点 但不是以 w为结点的边
			p = p->ilink; 
		else if(p->jvex == i && p->ivex != j) //情况2  就是指:这条边是以v为终点  但起点不是w的边   
			p = p->jlink;
		else
			break;
	
	//情况1
	if(p && p->ivex == i && p->jvex == j) {
		p = p->ilink;

		if(p && p->ivex == i)
			return p->jvex;
		else if(p && p->jvex == i)
			return p->ivex;
	}

	//情况2
	if(p && p->ivex == j && p->jvex == i) {
		p = p->jlink;

		if(p && p->ivex == i)
			return p->jvex;
		else if(p && p->jvex == i)
			return p->ivex;
	}


	return -1;
}


/*
* @description:插入一个顶点
*/
Status InsertVex(AMLGraph *G,VertexType v) {
	int i;

	i = (*G).vexnum;//赋予其一个下标值
	//在顶点数组中添加一个顶点
	(*G).adjmulist[i].data = v;//数据域赋值
	(*G).adjmulist[i].firstarc = NULL;//第一条指向空
	(*G).vexnum++;//数组数目增加

	return OK;
}


/*
* @description:插入一段弧
*/
Status InsertArc(AMLGraph *G,VertexType v,VertexType w) {
	int i,j;
	EBox *p;
	//放回两顶点在顶点向量数组中位置
	//首先返回这两个顶点在顶点数组中的位置
	i = LocateVex(*G,v);
	j = LocateVex(*G,w);


	if(i < 0 || j < 0)
		return ERROR;
	//为边表分配内存
	p = (EBox *) malloc(sizeof(struct EBox));

	if(!p)
		exit(OVERFLOW);

	///建立新节点
	//这一步操作就类似于在两个顶点之间画上一条线
	p->ivex = i;
	p->jvex = j;
	p->mark = unvisited;
	//注意每次插入新节点都是在链表的表头进行
	//采用头插法
	p->ilink = (*G).adjmulist[i].firstarc;
	p->jlink = (*G).adjmulist[j].firstarc;
	(*G).adjmulist[i].firstarc = p;
	(*G).adjmulist[j].firstarc = p;

	if((*G).kind == UDN) {
		//如果这是一个网图 还需要如数权值
		printf("please enter the weight of the arc:");
		scanf("%d",&p->weight);
	}


	return OK;

}



/*
 * @description:深度优先遍历图
 */
Status DFSTraverse(AMLGraph G) {
	int i;

	for(i = 0;i < G.vexnum ; i++) 
		visited[i] = FALSE;//先初始化访问结点  将其都设置位false  然后逐个访问
	//循环是为保证每个顶点都能被访问到
	for(i = 0; i < G.vexnum; i++) 
		if(!visited[i])
			DFS(G,i);//采用递归的方法

}


/*
 * @description:递归实现深度优先遍历
 */
void DFS(AMLGraph G,int i) {
	int j;
	EBox *p;

	printf("%d",G.adjmulist[i].data);
	visited[i] = TRUE;

	p = G.adjmulist[i].firstarc;

	while(p) {
		//如果这条边是以i为尾结点 那么讲头结点赋值给j,否则就将这条边的头结点赋值给j
		j = p->ivex == i ? p->jvex : p->ivex;
		if(!visited[j])
			DFS(G,j);//最后采用递归遍历 

		p = p->ivex == i ? p->ilink : p->jlink ;//然后遍历与顶点相同顶点的边  一层一层的访问
	}

}

AMLGraph.c

#include<stdio.h>
#include<stdlib.h>
#include"amlgraph.h"
void main(){
AMLGraph G;
CreateGraph(&G);
DFSTraverse(G);
printf("\n");

这是test.c
下面是测试的结果

please enter the kind of graph:0
please enter vexnum and arcnum:8,8
please enter each value of graph:1,2,3,4,5,6,7,8
please enter heads and tails:
1,2
1,3
2,4
2,5
3,6
3,7
4,8
5,8
13762584

源码

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值