图算法:1、邻接表实现图的深度优先遍历,广度优先遍历

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



你可能感兴趣的:(图的遍历)