另一篇文章:是全部采用递归实现dfs,bfs:http://blog.csdn.net/codeforme/article/details/6036864#,这篇文章存在内存泄漏问题
我的bfs采用队列实现,并且解决了内存泄漏问题
Graph.h
/************************************************************************/ /* 图的邻接表存储结构 这个与我的哈希算法时一样的:顶点表是主要的,里面存放的节点 是边表节点, 边表节点本身里面包含边表节点,建的主表是顶点表*/ /************************************************************************/ #ifndef GRAPH_H #define GRAPH_H #define MaxVertexNum 100 #define QueueSize 30 bool visited[MaxVertexNum]; typedef char VertexType; typedef int EdgeType; typedef struct node //边表结点 , { int adjvex; //邻接点域 ,注意,这里存储的是其他顶点在顶点表的下标 struct node* next; //域链 //若是要表示边上的权,则应增加一个数据域 }EdgeNode; typedef struct vnode //顶点边结点 { //VertexNode():firstedge(NULL){}//默认指针为空 VertexType vertex; //顶点域 ,注意:这里是顶点域的下标,用来表明内存节点的 EdgeNode* firstedge;//边表头指针 int index; //这里必须加上该顶点在顶点表中的下标,否则宽度优先搜索设置已经访问标记时会无法设定访问标记 void setIndex(int iIndex) { index = iIndex; } }VertexNode; typedef VertexNode AdjList[MaxVertexNum]; //AdjList是邻接表类型 typedef struct { AdjList adjlist; //邻接表 int n; //图中当前顶点数 int e; //图中当前边数 }ALGraph; //对于简单的应用,无须定义此类型,可直接使用AdjList类型 ALGraph* initALGraph(); bool DFS(ALGraph* a, int i); bool DFSTraverseM(ALGraph* a); bool BFSTraverseM(ALGraph* a); bool BFS(ALGraph* a, int i); #endif
#include "Graph.h" #include <stdio.h> #include <stdlib.h> #include "MyQueue.h" #include <queue> #include <iostream> using namespace std; ALGraph* initALGraph() { ALGraph* a = NULL; EdgeNode* e = NULL; int i, j, k; char v1, v2; printf("请输入顶点数和边数(输入格式为:顶点数,边数): "); scanf("%d %d", &i, &j); if(i<0 || j<0) return NULL; a = (ALGraph*)malloc(sizeof(ALGraph)); if(a == NULL) return NULL; a->n = i; a->e = j; //对顶点表的边表节点指针赋值为空,防止出现释放内存出现错误 for(int i = 0 ; i < MaxVertexNum ; i++) { //VertexNode vNode = a->adjlist[i]; //需要对vNode进行判空,不是所有的都已经被处理过了 //vNode.firstedge = NULL;//必须设置第一个边表节点的next为空,注意这里不要用局部变量 //vNode.vertex = 'd';//用于后续删除的判定标记,-1表示该节点无需内存释放 a->adjlist[i].firstedge = NULL; } for(i=0; i<a->n; i++) { printf("请输入顶点信息 每个顶点以回车作为结束: "); fflush(stdin); scanf("%c",&(a->adjlist[i].vertex)); // 读入顶点信息 ,这边存储的是字符信息 a->adjlist[i].firstedge=NULL; // 点的边表头指针设为空 a->adjlist[i].setIndex(i); } for(k=0; k<a->e; k++) { printf("请输入边的信息(输入格式为:i,j): "); fflush(stdin); scanf("%c,%c", &v1, &v2); for(i=0; v1!=a->adjlist[i].vertex; i++); //找到顶点对应的存储序号 for(j=0; v2!=a->adjlist[j].vertex; j++);//找到顶点对应的存储序号 e = (EdgeNode*)malloc(sizeof(EdgeNode));//也就是要遍历所有顶点表释放内存 e->adjvex = i;//注意:这里是顶点域的下标,用来表明内存节点的 e->next = a->adjlist[j].firstedge;//才用的是头插法 a->adjlist[j].firstedge = e; e = (EdgeNode*)malloc(sizeof(EdgeNode)); e->adjvex = j; e->next = a->adjlist[i].firstedge; a->adjlist[i].firstedge = e; } return a; } /************************************************************************/ /* 深度优先遍历 */ /************************************************************************/ bool DFS(ALGraph* a, int i) { if(a == NULL) return false; //printf("DFS: node %c:\n", a->adjlist[i].vertex); cout << a->adjlist[i].vertex << "," ; visited[i] = true; i = a->adjlist[i].firstedge->adjvex; if(!visited[i]) DFS(a, i); return true; } bool DFSTraverseM(ALGraph* a) { int i; if(a == NULL) return false; for(i=0; i<a->n; i++) visited[i] = false; for(i=0; i<a->n; i++) if(!visited[i]) DFS(a, i); return true; } //这个遍历的过程有些问题,因为边表节点与顶点表节点不同,因此必须获取第一个边表节点,进行释放内存 //参数:顶点表中第一个边表节点,遍历删除的过程,采用顺序删除 void freeList(EdgeNode* pNode) { EdgeNode* pDel; //如果边表为空,那么说明递归终止 while(pNode != NULL) { pDel = pNode; //如果后续不空 if(pNode->next) { pNode = pNode->next;//这里中断了 free(pDel); pDel = NULL; } //如果已经空了,直接退出 else { free(pDel); pDel = NULL; break; } } } //释放图:1先遍历所有顶点表,将顶点表中的边表释放(递归,从后向前释放),2最后释放图 void freeGraph(ALGraph* pGraph) { if(pGraph == NULL) { return ; } //释放链表 for(int i = 0 ; i < MaxVertexNum ; i++) { VertexNode vNode = pGraph->adjlist[i]; //需要对vNode进行判空,不是所有的都已经被处理过了 //if(vNode.vertex != 'd') //{ EdgeNode* pNode = vNode.firstedge; freeList(pNode); //} } //释放图 free(pGraph); } /************************************************************************/ /* 广度优先遍历(递归实现) */ /************************************************************************/ bool BFSTraverseM(ALGraph* a, int i) { if(a == NULL) return false; //初始化访问标记 for(int j=0; j <a->n; j++) visited[j] = false; //设定初始头结点,将该顶点表塞入到队列中 //visited[i] = true; //记住,队列中的元素类型为顶点,不是顶点表 queue<VertexNode> queueVertexNode; //VertexNode curNode = a->adjlist[i]; queueVertexNode.push(a->adjlist[i]); string sResult; while(! queueVertexNode.empty() ) { //获取队首结点 VertexNode curNode = queueVertexNode.front(); //如果当前节点已经访问过,弹出之后,过滤 if(visited[curNode.index]) { queueVertexNode.pop();//注意一定要弹出 continue; } //遍历队首结点的未访问子节点,入队 EdgeNode* pNode = curNode.firstedge; //讲该队首结点的所有未被访问过的边表结点入队 while(pNode) { int index = pNode->adjvex; if(!visited[index]) { queueVertexNode.push(a->adjlist[index]); } pNode = pNode->next; } //置当前结点为已经访问,当前结点自己的下表怎么获取,已经修改添加顶点在顶点表中的下表 visited[curNode.index] = true; //弹出该顶点(实际上是一个链表) queueVertexNode.pop(); //打印当前访问的结点,打印的是他的数据域 cout << curNode.vertex << "," ; } return true; } /* 预期输入: 顶点数 边数 7 7 顶点信息: 1 2 3 4 5 6 7 边信息: 1 2 2 3 3 1 3 4 3 5 3 7 4 6 预期输出: 深度优先搜索:1,3,7,2,4,6,5 广度优先搜索:1,3,2,7,5,4,6 */ void process() { ALGraph* pGraph = initALGraph(); cout << "深度优先搜索:" ; DFSTraverseM(pGraph); cout << endl << "广度优先搜索:" ; BFSTraverseM(pGraph, 0); freeGraph(pGraph); } int main(int argc,char* argv[]) { process(); getchar(); system("pause"); return 0; }