图的存储结构与遍历

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、顶点类型、图的类型以及边的结构

typedef int vertex;//顶点编号从0开始
typedef enum bool{
	true = 1, false = 0
}bool;
typedef enum Graphkind{
	DG=1, DN=2, UDG=3, UDN=4//图的种类:1.有向图 2.有向网 3.无向图 4.无向网
}Graphkind;
typedef struct edgenode {//边结构
	vertex v, w;//边的顶点v,w
	struct Union {
		int weight;
		int edge;
	}val;//表示权值或者表示是否存在边
}edge;

二、邻接矩阵存储

typedef struct Graph {
	int vexnum,edgenum;
	//vertex* v;顶点数组,用于顶点可能有数据时
	edge* (*matrix);//邻接矩阵
	Graphkind kind;
}*MGraph;

三、邻接表存储

typedef struct LGnode {//邻接表顶点数组
	//int val;//顶点存储信息时
	struct edge* first;//该顶点的第一条边
}LGnode;

typedef struct LGraph {
	LGnode* ptr;
	int vexnum,edgenum;//顶点数、边数
	Graphkind kind;
}*LGraph;

typedef struct edge {//邻接表边结构
	vertex end;//弧头
	struct edge*next;//下一条边
	int weight;
}Ledge;

四、图的建立

1.邻接矩阵建立无向图(网)

MGraph inite_Mgraph(int vnum, Graphkind kind) {//建一个空图
	MGraph g = (MGraph)malloc(sizeof(struct Graph));
	g->vexnum = vnum;
	//g->v = (vertex*)maclloc(sizeof(vertex)*vnum);
	g->matrix = (edge**)malloc(sizeof(edge*)*vnum);
	for (int i = 0; i < g->vexnum; i++) {
		(g->matrix)[i] = (edge*)malloc(sizeof(edge)*vnum);
	}
	g->kind = kind;
	for (vertex v = 0; v < g->vexnum; v++) {
		for (vertex w = 0; w < g->vexnum; w++) {
			if (g->kind == 3)
				(g->matrix)[v][w].val.edge = 0;//或者∞
			if (g->kind == 4)
				(g->matrix)[v][w].val.weight = 0;
		}
	}
	return g;
}
void create(MGraph g, edge* e) {//插入边e
	if (g->kind == 3) {//无向图1表示边存在
		(g->matrix)[e->v][e->w].val.edge = 1;
		(g->matrix)[e->w][e->v].val.edge = 1;
	}
	if (g->kind == 4) {
		(g->matrix)[e->v][e->w].val.weight = e->val.weight;
		(g->matrix)[e->w][e->v].val.weight = e->val.weight;
	}
}
MGraph buildMgraph() {
	int vnum, kind, edgenum;//顶点数,图类型,顶点关系,边数
	scanf_s("%d %d", &vnum, &kind);
	MGraph g = inite_Mgraph(vnum, kind);//建空图
	scanf_s("%d", &edgenum);
	edge* e = (edge*)malloc(sizeof(edge));
	for (int i = 0; i < edgenum; i++) {//插入边
		if (g->kind == 3) {//无向图
			scanf_s("%d %d", &e->v, &e->w);
			create(g, e);
		}
		if (g->kind == 4) {//无向网
			scanf_s("%d %d %d", &e->v, &e->w, &e->val.weight);
			create(g, e);
		}
	}
	/*for (vertex v= 0; v < g->vexnum; v++) {//若顶点需要存储信息时
		scanf_s("%d", &g->v[v]);
	}*/
	return g;
}

2.邻接表建立有向图(网)

LGraph inite_Lgraph(int vnum, Graphkind kind) {//建一个空图
	LGraph g = (LGraph)malloc(sizeof(struct LGraph));
	g->vexnum = vnum;
	g->kind = kind;
	g->ptr = (LGnode*)malloc(sizeof(LGnode));
	for (vertex v = 0; v < g->vexnum; v++)
		g->ptr[v].first = NULL;//初始化所有顶点均无第一条边
	return g;
}
void insertedge(LGraph g, edge* e) {
	Ledge *q = (Ledge*)malloc(sizeof(Ledge));
	q->end = e->w;
	if (g->kind == 2)//有向网存储权值
		q->weight = e->val.weight;
	q->next = g->ptr[e->v].first;
	g->ptr[e->v].first = q;
	//若存储无向图还需插入另一边
	//Ledge *t = (Ledge*)malloc(sizeof(Ledge));
	//t->end = e->v;
	//t->weight = e->val.weight;
	//t->next=g->ptr[e->w].first;
	//g->ptr[e->w].first=t;
}
LGraph buildLgraph() {
	int vnum, edgenum, kind;
	scanf_s("%d %d", &vnum, &kind);
	LGraph g = inite_Lgraph(vnum, kind);//建一个空图
	scanf_s("%d", &edgenum);
	edge*e = (edge*)malloc(sizeof(edge));
	for (int i = 0; i < edgenum; i++) {//插入边
		if (g->kind == 1) {//有向图
			scanf_s("%d %d", &e->v, &e->w);
			insertedge(g, e);
		}
		if (g->kind == 2) {//有向网
			scanf_s("%d %d %d", &e->v, &e->w, &e->val.weight);
			insertedge(g, e);
		}
	}
	return g;
}

五、遍历

1.DFS遍历邻接矩阵

void dfs(MGraph g, vertex v, bool*visited) {
	visited[v] = true;//更新visited数组
	for (vertex w = 0; w < g->vexnum; w++) {
		if ((g->matrix)[v][w].val.edge == 1 || (g->matrix)[v][w].val.weight) {//若v,w间存在边或有权值
			if (g->kind == 3)
				printf("%d<->%d\n", v, w);
			if (g->kind == 4)
				printf("%d<->%d %d\n", v, w, (g->matrix)[v][w].val.weight);
			if (!visited[w])//若为访问过w,则对w做dfs
				dfs(g, w, visited);
		}
	}
}
void DFS(MGraph g) {//对G中每个顶点做DFS
	bool* visited = (bool*)malloc(sizeof(g->vexnum));//设置一个标记数组
	for (vertex v = 0; v < g->vexnum; v++)visited[v] = false;
	for (vertex v = 0; v < g->vexnum; v++) {
		if (!visited[v]) {
			dfs(g, v, visited);
		}
	}
}

2.DFS遍历邻接表

void Ldfs(LGraph g, vertex v, bool *visited) {
	visited[v] = true;
	Ledge*p = g->ptr[v].first;
	while (p) {//对v的每个邻接点end
		if (g->kind == 1)
			printf("%d->%d\n", v, p->end);
		if (g->kind == 2)
			printf("%d->%d %d\n", v, p->end, p->weight);
		if (!visited[p->end])
			Ldfs(g, p->end, visited);
		p = p->next;
	}
}
void LDFS(LGraph g) {
	bool *visited = (bool*)malloc(sizeof(g->vexnum));
	for (vertex v = 0; v < g->vexnum; v++)visited[v] = false;
	for (vertex v = 0; v < g->vexnum; v++) {
		if (!visited[v])
			Ldfs(g, v, visited);
	}
}

3.BFS遍历邻接矩阵

void BFS(MGraph g,vertex u) {//从某一顶点u出发做BFS
	bool *visited = (bool*)malloc(sizeof(g->vexnum));
	for (vertex v = 0; v < g->vexnum; v++)visited[v] = false;
	Queue q = inite();
	enqueue(q, u);
	visited[u] = true;
	while (!isempty(q)) {
		vertex v = dequeue(q)->v;
		for (vertex w = 0; w < g->vexnum; w++) {
			if (g->kind == 3) {
				if ((g->matrix)[v][w].val.edge) {//若存在边v,w
					if (!visited[w]) {
						printf("%d<->%d\n", v, w);
						visited[w] = true;
						enqueue(q, w);
					}
				}
			}
			if (g->kind == 4){
				if((g->matrix)[v][w].val.weight)//若存在边v,w
					if (!visited[w]) {
						printf("%d<->%d %d\n", v, w, (g->matrix)[v][w].val.weight);
						visited[w] = true;
						enqueue(q, w);
				}
			}
		}
	}
}

4.BFS遍历邻接表

void LBFS(LGraph g,vertex u) {
	bool* visited = (bool*)malloc(sizeof(g->vexnum));
	for (vertex v = u; v < g->vexnum; v++)visited[v] = false;
	Queue q = inite();
	enqueue(q, u);
	visited[u] = true;
	while (!isempty(q)) {
		vertex v = dequeue(q)->v;
		Ledge*t = g->ptr[v].first;
		while (t) {
			if (!visited[t->end]) {
				visited[t->end] = true;
				if (g->kind == 1)
					printf("%d->%d\n", v, t->end);
				if (g->kind == 2)
					printf("%d->%d %d\n", v, t->end, t->weight);
				enqueue(q, t->end);
			}
			t = t->next;
		}
	}
}

六、完整程序

1.函数部分头文件

//邻接矩阵操作集
MGraph inite_Mgraph(int vnum,Graphkind kind);
void create(MGraph g, edge* e);
MGraph buildMgraph();
void showMgraph(MGraph g)
void dfs(MGraph g, vertex v, bool*visited);
void DFS(MGraph g);
void BFS(MGraph g,vertex u);
//邻接表操作集
LGraph inite_Lgraph(int vnum, Graphkind kind);
void insertedge(LGraph g, edge* e);
LGraph buildLgraph();
void showLgraph(LGraph g)
void Ldfs(LGraph g, vertex v, bool *visited);
void LDFS(LGraph g);
void LBFS(LGraph g, vertex u);
//队列
typedef struct qnode {
	vertex v;
	struct qnode*next;
}qnode;
typedef struct queue {
	qnode*head;
	qnode*tail;
	int num;
}*Queue;
Queue inite();
int isempty(Queue q);
void enqueue(Queue q, vertex u);
qnode* dequeue(Queue q);

2.main

int main() {
	MGraph p = buildMgraph();
	LGraph g = buildLgraph();
	showMgraph(p);
	printf("\n");
	showLgraph(g);
	DFS(p);
	LDFS(g);
	BFS(p,0);//从任一顶点做BFS
	LBFS(g,0);
	return 0;
}
void showMgraph(MGraph g) {
	for (vertex v = 0; v < g->vexnum; v++) {
		for (vertex w = 0; w < g->vexnum; w++) {
			if(g->kind==3)
				printf("%d",(g->matrix)[v][w].val.edge);
			if(g->kind==4)
				printf("%d", (g->matrix)[v][w].val.weight);
		}
		printf("\n");
	}
}
void showLgraph(LGraph g) {
	for (vertex v = 0; v < g->vexnum; v++) {
		printf("%d:", v);
		Ledge*e = g->ptr[v].first;
		while (e) {
			printf("->%d", e->end);
			e = e->next;
		}
		printf("->NULL\n");
	}
}
Queue inite()
{
	Queue q = (Queue)malloc(sizeof(struct queue));
	q->head = q->tail = NULL;
	q->num = 0;
}
int isempty(Queue q)
{
	if (q->num == 0)return 1;
	else return 0;
}
void enqueue(Queue q, vertex v)
{
	if (q->head == NULL) {
		qnode* tmp = (qnode*)malloc(sizeof(qnode));
		tmp->v = v;
		tmp->next = NULL;
		q->head = tmp;
		q->tail = tmp;
	}
	else {
		qnode* tmp = (qnode*)malloc(sizeof(qnode));
		tmp->v = v;
		tmp->next = q->tail;
		q->tail = tmp;
	}
	q->num++;
}
qnode* dequeue(Queue q)
{
	if (q->num == 0)return NULL;
	if (q->num == 1) {
		q->num = 0;
		qnode*tmp = q->head;
		q->head = q->tail = NULL;
		return tmp;
	}
	qnode*tmp = q->head;
	qnode*p = q->tail;
	while (p->next != q->head) {
		p = p->next;
	}
	q->head = p;
	q->num--;
	return tmp;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值