观数据结构写代码(40) 无向图的深度优先生成树与广度优先生成树

看数据结构写代码(40) 无向图的深度优先生成树与广度优先生成树

图的深度优先遍历 和 广度 优先 遍历 算法中的 每一次 最外层 循环 都 产生 一个 无向图 的 连通分量,每一个连通分量,都可以产生一个生成树,将这些生成树合在 一起 就是 一个 森林。 用 树的 孩子 兄弟 链表 表示法 来 表示 这个 森林, 就是 这一节 算法的  内容。

深度优先森林 代码 :

//深度优先生成森林
void dfsTree(AMLGraph g,int i,Tree * t,bool isVisited[]){
	isVisited[i] = true;
	bool isFirst = true;
	Tree p,q = NULL;
	for (int next = firstAdj(g,i); next != -1; next = nextAdj(g,i,next)){
		if (isVisited[next] == false){
			p = makeTreeNode(g.adjMuList[next].vexName);
			if (isFirst){
				(*t)->firstChild = p,isFirst = false;
			}
			else{
				q->nextSibling = p;
			}
			q = p;
			dfsTree(g,next,&q,isVisited);
		}

	}
}


void dfsForest(AMLGraph g,Tree * t){
	bool isVisited[MAX_VEX_NUM] = {false};
	*t = NULL;
	Tree p,q;
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			p = makeTreeNode(g.adjMuList[i].vexName);//每一次循环都是一颗生成树.
			if (*t == NULL){//第一个是根节点
				*t = p;
			}
			else{//其余生成树 是 第一颗 生成树的 兄弟
				q->nextSibling = p;
			}
			q = p;//保存上一个树
			dfsTree(g,i,&q,isVisited);
		}
	}
}
广度优先生成森林代码:

//广度优先生成森林
void bfsForest(AMLGraph g,Tree * t){
	bool isVisited[MAX_VEX_NUM] = {false};
	Tree treeArray[MAX_VEX_NUM] = {NULL};//记录所有顶点的 树节点坐标.
	//因为要 找到 遍历的 树节点的 父亲 是谁.(这一句p = treeArray[top];)
	Tree p,q,r;
	LinkQueue queue;
	queueInit(&queue);
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			p = makeTreeNode(g.adjMuList[i].vexName);
			if (i == 0){//第一颗生成树..
				*t = p;
			}
			else{//其他生成树是 第一颗生成树的 孩子兄弟链表的 兄弟
				//(*t)->nextSibling = p; 这样写 就只有 一个兄弟节点了..
				q->nextSibling = p;
			}
			q = p;
			treeArray[i] = p;
			isVisited[i] = true;
			enqueue(&queue,i);
			while (!queueEmpty(queue)){
				int top;
				dequeue(&queue,&top);
				bool isFirst = true;
				for (int next = firstAdj(g,top);next != -1; next = nextAdj(g,top,next)){
					if (isVisited[next] == false){
						isVisited[next] = true;
						r = makeTreeNode(g.adjMuList[next].vexName);
						treeArray[next] = r;
						if (isFirst){
							p = treeArray[top];
							p->firstChild = r,isFirst = false;
						}
						else{
							p->nextSibling = r;
						}
						p = r;
						enqueue(&queue,next);
					}
				}
			}
		}
	}
	queueDestory(&queue);
}
在写广度 优先生成森林代码中,犯了 两个错误:

1.

//(*t)->nextSibling = p; 这样写 就只有 一个兄弟节点了..
q->nextSibling = p;

2.

没有 写 这句话:

p = treeArray[top];

后来 将所有 顶点的坐标 存到 数组中,好查找 节点的 父亲节点。


详细源代码如下:

工程文件网盘地址:点击打开链接

// AMLGraph.cpp : 定义控制台应用程序的入口点。
//无向图的邻接多重表

#include "stdafx.h"
#include <cstdlib>
#include "queue.h"
#include "BinaryTree.h"

#define MAX_VEX_NUM 20

enum E_VisitIf
{
	unvisited = 0,
	visited = 1,
};
struct ArcNode
{
	E_VisitIf mark;
	int iIndex,jIndex;//顶点i,j在图中的位置
	ArcNode * iNext;//与i顶点点相关的下一个弧
	ArcNode * jNext;//与j顶点点相关的下一个弧
};

struct VNode
{
	char vexName;
	ArcNode * head;//头指针
};

struct AMLGraph
{
	VNode adjMuList[MAX_VEX_NUM];//顶点数组
	int vexNum,arcNum;
};

//获取弧 的 头节点
ArcNode * getHeadNode(){
	ArcNode * pNode = (ArcNode *)malloc(sizeof(ArcNode));
	if (pNode){
		pNode->iIndex = pNode->jIndex = -1;
		pNode->iNext = pNode->jNext = NULL;
		pNode->mark = unvisited;
	}
	return pNode;
}

ArcNode * getArcNode(int iIndex,int jIndex){
	ArcNode * pNode = getHeadNode();
	if (pNode){
		pNode->iIndex = iIndex;
		pNode->jIndex = jIndex;
	}
	return pNode;
}

int vexLocation(AMLGraph g,char vex){
	for (int i = 0; i < g.vexNum; i++){
		if (g.adjMuList[i].vexName == vex){
			return i;
		}
	}
	return -1;
}

void createGrahp(AMLGraph * g){
	printf("输入图的顶点数 和 边(弧)数\n");
	scanf("%d%d%*c",&g->vexNum,&g->arcNum);  
    //构造顶点集  
    printf("请输入顶点集\n");  
    for (int i = 0; i < g->vexNum; i++){  
        char name;
		scanf("%c",&name);
		g->adjMuList[i].vexName = name;
		g->adjMuList[i].head = getHeadNode();//建立 头节点,并让头指针指向头节点
    }  
    //构造顶点关系  
    fflush(stdin);  
    printf("请输入顶点的关系\n");  
    for (int i = 0; i < g->arcNum; i++){  
        char vex1,vex2;
		scanf("%c%c%*c",&vex1,&vex2);  
		int location1 = vexLocation(*g,vex1);
		int location2 = vexLocation(*g,vex2);
		ArcNode * pNode = getArcNode(location1,location2);
		pNode->iNext = g->adjMuList[location1].head->iNext;
		g->adjMuList[location1].head->iNext = pNode;
		pNode->jNext = g->adjMuList[location2].head->iNext;
		g->adjMuList[location2].head->iNext = pNode;
    }  
}


void destoryGraph(AMLGraph * g){
	for (int i = 0; i < g->vexNum; i++){
		ArcNode * next = g->adjMuList[i].head->iNext;
		while (next != NULL){
			ArcNode * freeNode = next;
			next = next->iIndex == i ? next->iNext : next->jNext;
			if (freeNode->iIndex == i){////只释放 iIndex 等于 i的节点,要不会多次释放
				free(freeNode);
			}
		}
		free(g->adjMuList[i].head);
		g->adjMuList[i].head = NULL;
		g->adjMuList[i].vexName = ' ';
		g->vexNum = g->arcNum = 0;
	}
}

//顶点vex1 和顶点vex2 是否相邻
bool graphIsAdj(AMLGraph g,char vex1,char vex2){
	int location = vexLocation(g,vex1);
	ArcNode * next = g.adjMuList[location].head->iNext;
	while (next != NULL){
		if (g.adjMuList[next->iIndex].vexName == vex2 || g.adjMuList[next->jIndex].vexName == vex2){
			return true;
		}
		next = next->iIndex == location ? next->iNext : next->jNext;
	}
	return false;
}

int graphDegree(AMLGraph g,char vex){
	int degree = 0;
	int location = vexLocation(g,vex);
	ArcNode * next = g.adjMuList[location].head->iNext;//计算所有出度
	while (next != NULL){
		degree++;
		next = next->iIndex == location ? next->iNext : next->jNext;
	}
	return degree;
}


//插入边(弧)
void insertArc(AMLGraph * g,char vex1,char vex2){
	int location1 = vexLocation(*g,vex1);
	int location2 = vexLocation(*g,vex2);
	ArcNode * node = getArcNode(location1,location2);
	node->iNext = g->adjMuList[location1].head->iNext;
	g->adjMuList[location1].head->iNext = node;
	node->jNext = g->adjMuList[location2].head->iNext;
	g->adjMuList[location2].head->iNext = node;
	g->arcNum ++;
}
//删除边(弧)
void deleteArc(AMLGraph * g,char vex1,char vex2){
	g->arcNum--;
	int location1 = vexLocation(*g,vex1);
	int location2 = vexLocation(*g,vex2);
	ArcNode * next = g->adjMuList[location1].head->iNext;
	ArcNode * pre = g->adjMuList[location1].head;
	while (next != NULL){
		if (next->iIndex == location2){
			if (pre == g->adjMuList[location1].head || pre->iIndex == location1){//删除的是第一个节点.或者 前驱的index = location1
				pre->iNext = next->jNext;
			}
			else{
				pre->jNext = next->jNext;
			}
			break;
		}
		else if(next->jIndex == location2){
			if (pre == g->adjMuList[location1].head || pre->iIndex == location1){//删除的是第一个节点.或者 前驱的index = location1
				pre->iNext = next->iNext;
			}
			else{
				pre->jNext = next->iNext;
			}
			break;
		}
		pre = next;
		next = next->iIndex == location1 ? next->iNext : next->jNext;
	}
	next = g->adjMuList[location2].head->iNext;
	pre = g->adjMuList[location2].head;
	while (next != NULL){
		if (next->iIndex == location1){
			if (pre == g->adjMuList[location2].head || pre->iIndex == location2){//删除的是第一个节点.或者 前驱的index = location1
				pre->iNext = next->jNext;
			}
			else{
				pre->jNext = next->jNext;
			}
			free(next);
			break;
		}
		else if(next->jIndex == location1){
			if (pre == g->adjMuList[location2].head || pre->iIndex == location2){//删除的是第一个节点.或者 前驱的index = location1
				pre->iNext = next->iNext;
			}
			else{
				pre->jNext = next->iNext;
			}
			free(next);
			break;
		}
		pre = next;
		next = next->iIndex == location2 ? next->iNext : next->jNext;
	}
}
//插入顶点
void insertVex(AMLGraph * g, char vex){
	if (g->vexNum < MAX_VEX_NUM){
		g->adjMuList[g->vexNum].vexName = vex;
		g->adjMuList[g->vexNum].head = getHeadNode();
		g->vexNum++;
	}
}
//删除顶点
void deleteVex(AMLGraph * g,char vex){
	int location = vexLocation(*g,vex);
	//删除顶点 同样需要 遍历整个 图 查找 与 vex 相关的弧节点
	for (int i = 0; i < g->vexNum; i++){
		ArcNode * next = g->adjMuList[i].head->iNext;
		while (next != NULL){
			if (next->iIndex == location || next->jIndex == location){
				ArcNode * delNode = next;
				next = next->iIndex == location ? next->iNext : next->jNext;
				char delData1 = g->adjMuList[delNode->iIndex].vexName;
				char delData2 = g->adjMuList[delNode->jIndex].vexName;
				deleteArc(g,delData1,delData2);
			}
			else{
				next = next->iIndex == location ? next->iNext : next->jNext;
			}
		}
	}
	//更改因删除顶点 而导致的元素位置变化..
	for (int i = 0; i < g->vexNum; i++){
		ArcNode * next = g->adjMuList[i].head->iNext;
		while (next != NULL){
			if (next->iIndex == i){
				if(next->iIndex > location){
				next->iIndex --;
				}
				if(next->jIndex > location){
					next->jIndex --;
				}
			}
			next = next->iIndex == location ? next->iNext : next->jNext;
		}
	}
	free(g->adjMuList[location].head);//释放头节点
	//vex下面的 顶点上移
	for (int i = location + 1; i < g->vexNum; i++){
		g->adjMuList[i-1] = g->adjMuList[i];
	}
	g->vexNum --;
}


void printGrahp(AMLGraph g){
	for (int i = 0; i < g.vexNum; i++){
		printf("%c的 邻接点有:",g.adjMuList[i].vexName);
		ArcNode * next = g.adjMuList[i].head->iNext;//删除所有弧尾
		while (next != NULL){
			int index = next->iIndex == i ? next->jIndex : next->iIndex;
			printf("%c",g.adjMuList[index].vexName);
			next = next->iIndex == i ? next->iNext : next->jNext;
		}
		printf("\n");
	}
}

int firstAdj(AMLGraph g,int location){
	ArcNode * next = g.adjMuList[location].head->iNext;
	if (next != NULL)
	{
		int index = next->iIndex == location ? next->jIndex : next->iIndex;
		return index;
	}
	return -1;
}

int nextAdj(AMLGraph g,int location1 ,int location2){
	ArcNode * next = g.adjMuList[location1].head->iNext;
	while (next != NULL){
		if (next->iIndex == location2 || next->jIndex == location2){
			next = next->iIndex == location1 ? next->iNext : next->jNext;
			break;
		}
		next = next->iIndex == location1 ? next->iNext : next->jNext;
	}
	if (next != NULL){
		int index = next->iIndex == location1 ? next->jIndex : next->iIndex;
		return index;
	}
	return -1;
}
/*
void dfs(AMLGraph g,int i,bool * isVisitedArray){
	printf("%c",g.adjMuList[i].vexName);
	isVisitedArray[i] = true;
	for (int next = firstAdj(g,i); next != -1 ; next = nextAdj(g,i,next)){
		if (isVisitedArray[next] == false){
			dfs(g,next,isVisitedArray);
		}
	}
}
//深度优先搜索遍历
void dfsTraver(AMLGraph g){
	bool isVisited[MAX_VEX_NUM] = {false};
	printf("----------深度优先遍历------------------\n");
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			dfs(g,i,isVisited);
		}
	}
	printf("\n");
}
//广度优先搜索遍历
void bfsTraverse(AMLGraph g){
	bool isVisited[MAX_VEX_NUM] = {false};
	printf("----------广度优先遍历------------------\n");
	LinkQueue queue;
	queueInit(&queue);
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			printf("%c",g.adjMuList[i].vexName);
			isVisited[i] = true;
			enqueue(&queue,i);
			while (!queueEmpty(queue)){
				int top;
				dequeue(&queue,&top);
				for (int next = firstAdj(g,top);next != -1 ; next = nextAdj(g,top,next)){
					if (isVisited[next] == false){
						printf("%c",g.adjMuList[next].vexName);
						isVisited[next] = true;
						enqueue(&queue,next);
					}
				}
			}
		}
	}
	queueDestory(&queue);
}

void dfsTree(AMLGraph g,int v,Tree * t,bool * isVisited){
	isVisited[v] = true;
	bool first = true;
	Tree p,q= NULL;
	for (int next = firstAdj(g,v);next != -1 ;next = nextAdj(g,v,next)){
		if (isVisited[next] == false){
			p = makeTreeNode(g.adjMuList[next].vexName);
			if (first){
				(*t)->firstChild = p;first = false;
			}
			else{
				q->nextSibling = p;
			}
			q = p;
			dfsTree(g,next,&q,isVisited);
		}
	}
}

//深度优先遍历生成森林
void dfsForest(AMLGraph g,Tree * tree){
	bool isVisited[MAX_VEX_NUM] = {false};
	*tree = NULL;
	Tree p,q;
	for (int i = 0; i <g.vexNum ; i++){
		if (isVisited[i] == false){
			p = makeTreeNode(g.adjMuList[i].vexName);
			if (!*tree){
				*tree = p;//根节点.
			}
			else{
				q->nextSibling = p;
			}
		}
		q = p;//q指向当前生成树的根..
		dfsTree(g,i,&p,isVisited);
	}
}
*/
void dfs(AMLGraph g,int i,bool isVisited[]){
	printf("%c",g.adjMuList[i].vexName);
	isVisited[i] = true;
	for (int next = firstAdj(g,i); next != -1; next = nextAdj(g,i,next)){
		if (isVisited[next] == false){
			dfs(g,next,isVisited);
		}
	}
}

//深搜
void dfsTraverse(AMLGraph g){
	bool isVisited[MAX_VEX_NUM] = {false};
	printf("---------深度优先搜索遍历---------\n");
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){//未访问过
			dfs(g,i,isVisited);
		}
	}
	printf("\n");
}

//广搜
void bfsTraverse(AMLGraph g){
	bool isVisited[MAX_VEX_NUM] = {false};
	printf("---------广度优先搜索遍历---------\n");
	LinkQueue queue;
	queueInit(&queue);
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			enqueue(&queue,i);
			printf("%c",g.adjMuList[i].vexName);
			isVisited[i] = true;
			while (!queueEmpty(queue)){
				int top;
				dequeue(&queue,&top);
				for (int next = firstAdj(g,top); next != -1; next = nextAdj(g,top,next)){
					if (isVisited[next] == false){
						printf("%c",g.adjMuList[next].vexName);
						isVisited[next] = true;
						enqueue(&queue,next);
					}
				}
			}
		}
	}
	queueDestory(&queue);
	printf("\n");
}

//深度优先生成森林
void dfsTree(AMLGraph g,int i,Tree * t,bool isVisited[]){
	isVisited[i] = true;
	bool isFirst = true;
	Tree p,q = NULL;
	for (int next = firstAdj(g,i); next != -1; next = nextAdj(g,i,next)){
		if (isVisited[next] == false){
			p = makeTreeNode(g.adjMuList[next].vexName);
			if (isFirst){
				(*t)->firstChild = p,isFirst = false;
			}
			else{
				q->nextSibling = p;
			}
			q = p;
			dfsTree(g,next,&q,isVisited);
		}

	}
}


void dfsForest(AMLGraph g,Tree * t){
	bool isVisited[MAX_VEX_NUM] = {false};
	*t = NULL;
	Tree p,q;
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			p = makeTreeNode(g.adjMuList[i].vexName);//每一次循环都是一颗生成树.
			if (*t == NULL){//第一个是根节点
				*t = p;
			}
			else{//其余生成树 是 第一颗 生成树的 兄弟
				q->nextSibling = p;
			}
			q = p;//保存上一个树
			dfsTree(g,i,&q,isVisited);
		}
	}
}

//广度优先生成森林
void bfsForest(AMLGraph g,Tree * t){
	bool isVisited[MAX_VEX_NUM] = {false};
	Tree treeArray[MAX_VEX_NUM] = {NULL};//记录所有顶点的 树节点坐标.
	//因为要 找到 遍历的 树节点的 父亲 是谁.(这一句p = treeArray[top];)
	Tree p,q,r;
	LinkQueue queue;
	queueInit(&queue);
	for (int i = 0; i < g.vexNum; i++){
		if (isVisited[i] == false){
			p = makeTreeNode(g.adjMuList[i].vexName);
			if (i == 0){//第一颗生成树..
				*t = p;
			}
			else{//其他生成树是 第一颗生成树的 孩子兄弟链表的 兄弟
				//(*t)->nextSibling = p; 这样写 就只有 一个兄弟节点了..
				q->nextSibling = p;
			}
			q = p;
			treeArray[i] = p;
			isVisited[i] = true;
			enqueue(&queue,i);
			while (!queueEmpty(queue)){
				int top;
				dequeue(&queue,&top);
				bool isFirst = true;
				for (int next = firstAdj(g,top);next != -1; next = nextAdj(g,top,next)){
					if (isVisited[next] == false){
						isVisited[next] = true;
						r = makeTreeNode(g.adjMuList[next].vexName);
						treeArray[next] = r;
						if (isFirst){
							p = treeArray[top];
							p->firstChild = r,isFirst = false;
						}
						else{
							p->nextSibling = r;
						}
						p = r;
						enqueue(&queue,next);
					}
				}
			}
		}
	}
	queueDestory(&queue);
}

//邻接多重表
int _tmain(int argc, _TCHAR* argv[])
{
	AMLGraph g;
	createGrahp(&g);
	printGrahp(g);
	dfsTraverse(g);
	bfsTraverse(g);
	Tree tree;
	dfsForest(g,&tree);
	printf("\n----------深度优先遍历生成森林(先序遍历)------------------\n");
	preOrderTraverse(tree);
	treeDestory(&tree);
	bfsForest(g,&tree);
	printf("\n----------广度优先遍历生成森林(先序遍历)------------------\n");
	preOrderTraverse(tree);
	treeDestory(&tree);
	destoryGraph(&g);
	return 0;
}

运行截图:

观数据结构写代码(40) 无向图的深度优先生成树与广度优先生成树