算法 -图的遍历

本文介绍了图的深度优先遍历和广度优先遍历两种基本算法,并通过具体代码实现展示了这两种遍历方式的具体操作过程及运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图的遍历

继续上一次计算两个节点之间的所有路径,这次采用深度优先遍历与广度优先遍历算法来遍历整个图

图如下:


1、深度优先遍历:

思想

利用递归,与树的遍历不同的是,可能在图中某些节点之间是不连通的。本代码中使用的是递归,当然也是可以使用栈的非递归形式

代码:

#include <stack>
#include <queue>
#include <iostream>
using namespace std;

#define  NUM 12
#define MAX_PATH 100
struct Node
{
	int key;
	int flag;
	Node()
	{
		flag=0;
	}
};
template<class T>
class Queue:public queue<T>
{
public:
	T dequeue()
	{
		T tmp=front();
		queue<T>::pop();
		return tmp;
	}
	void enqueue(const T&e1)
	{
		push(e1);
	}
	bool isEmpty()
	{
		return empty();
	}
};

class Graph
{
public:
	int resultPath[MAX_PATH][NUM];//寻找所有路径
	bool Mark[NUM];//标记是否已经访问
public: 
	Graph()
	{
		Reset();
	}

	//将矩阵中的元素置为空
	void Reset()
	{
		for (int i=0;i<NUM;i++)
		{
			for (int j=0;j<MAX_PATH;j++)
			{
				resultPath[i][j]=0;
			}

			Mark[i]=false;
		}
	}

	void test()
	{
		int Matrix[NUM][NUM]={
			{0,1,0,1,0,0,0,0,0,0,0,0}, //A
			{1,0,1,0,0,0,0,0,0,0,0,0},//B
			{0,1,0,1,1,0,0,0,0,0,0,0},//C
			{1,0,1,0,0,1,0,0,0,0,0,0}, //D
			{0,0,1,0,0,0,1,0,0,0,0,0}, //E
			{0,0,0,1,0,0,1,1,0,0,0,0}, //F
			{0,0,0,0,1,1,0,0,0,0,0,0}, //G
			{0,0,0,0,0,1,0,0,0,0,0,0},//H
			{0,0,0,0,0,0,0,0,0,1,0,1},//I
			{0,0,0,0,0,0,0,0,1,0,1,1},//J
			{0,0,0,0,0,0,0,0,0,1,0,0},//K
			{0,0,0,0,0,0,0,0,1,1,0,0}//L
		};
		findPathBetweenTwoNode(Matrix);//找到所有的简单路径
		DFE(Matrix);//图的遍历,采用深度优先遍历算法
	

	}

	
	/************************************************************************/
	/* 函数功能:图的遍历
	   参数说明:vNum,顶点的个数
	             Matrix 邻接图
	*/
	/************************************************************************/
	void DFE(int Matrix[NUM][NUM])
	{

		//////////////////////深度优先遍历//////////////////////////////////
		Reset();//将元素置空
		int result[NUM]={0};//存放遍历结果
		int nPos=0;
		for(int i=0;i<NUM;i++)
		{
			deapFirstSearch(Matrix,result,nPos,i);//进行深度优先遍历算法
		}

		cout<<"遍历的顺序为:"<<endl;
		for (int i=0;i<NUM;i++)
		{
			cout<<result[i]<<"  "; 
		}

		///////////////////////广度优先遍历////////////////////////
		Reset();
		for (int i=0;i<NUM;i++)
		{
			result[i]=0;//清空数据
		}

		breadFirstSearch(Matrix,result);//进行广度优先遍历算法
		cout<<endl<<"广度遍历的顺序为:"<<endl;
		for (int i=0;i<NUM;i++)
		{
			cout<<result[i]<<"  "; 
		}
	}

	/************************************************************************/
	/*函数功能:深度优先遍历
	  参数说明:Matrix 矩阵
	*/
	/************************************************************************/
	void deapFirstSearch(int Matrix[NUM][NUM],int *result,int &nResultPos,int nSearchPos)
	{
		if (Mark[nSearchPos]==false)
		{
			*(result+nResultPos)=(nSearchPos+1);//索引是从0开始的
			Mark[nSearchPos]=true;
			nResultPos++;
			for (int i=0;i<NUM;i++)
			{
				if (Matrix[nSearchPos][i]==1)
				{
					deapFirstSearch(Matrix,result,nResultPos,i);
				}
			}
		}
	}




运行结果:


2、广度优先遍历
上面已经将广度优先的代码附上,主要利用的是队列,利用标记来表明是否已经访问过了
    //广度优先遍历算法
	//思想:利用队列
	void breadFirstSearch(int Matrix[NUM][NUM],int *result)
	{
		Queue<int>tempQueue;//定义队列
		int nSearchPos=0;//顶点遍历的索引,用以判断当前顶点是否已经遍历过
		int nResulPos=0;//索引遍历结果的元素

		while(nSearchPos<NUM)
		{
			if (Mark[nSearchPos]==false)//当节点还没有访问
			{
				tempQueue.enqueue(nSearchPos);//入队列
				Mark[nSearchPos]=true;//标识已经访问过
				while(!tempQueue.isEmpty())//当队列不为空
				{
					int dataPos=tempQueue.dequeue();//取出队最前面的元素
					result[nResulPos]=(dataPos+1);//存入结果集中
					nResulPos++;
					for (int i=0;i<NUM;i++)
					{
						if (Matrix[dataPos][i]==1&&Mark[i]==false)//判断与该节点是否有联通且该节点没有被访问过
						{
							tempQueue.enqueue(i);//出队列
							Mark[i]=true;//标记为已访问,这里很关键。试想将Mark放在for循环的外面??造成尽管有的节点已经入队列了,但是因为没有标记,所以再次的入队列,死循环
						}
					}

				}
			}
			nSearchPos++;//顶点索引加1
		}
		
	}
};

运行结果:


小结:
1)利用好队列与栈
2)小小标记用途多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值