另一篇文章:是全部采用递归实现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
Graph.cpp
#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;
}