无向图的深度优先搜索与广度优先搜索

图的简述:

图是一种复杂的数据结构,图(Graph)是由顶点(Vertex)组成的非空有穷集合和顶点之间的边(Edge)组成。

图的边可以由权值(weight),也可以没有,有权值的图称为网图。

图的边也可以有方向,没有方向的为无向图,有方向的为有向图。

图很复杂,就需要复杂的方式来表示图,一般简单的使用邻接矩阵和邻接表来表示,还有十字链表和邻接多重表等,这里只介绍前两种的实现。

无向图的邻接矩阵结构表示:

邻接矩阵简单也方便理解,即用一个一维数组储存顶点,用另一个二维数组储存各个顶点之间的边的信息。

无向图的邻接矩阵是一个对称矩阵,即arc[i][j]=arc

C++实现:

typedef char VertexType;        //顶点类型 ,默认为char
typedef int EdgeType;              //边的权值  默认int
#define MAXVERTEX 100          //最大的顶点数

//邻接矩阵的结构
typedef struct MGraph
{
	VertexType vexs[MAXVERTEX];     //顶点数组
	EdgeType arc[MAXVERTEX][MAXVERTEX];    //邻接矩阵  即边数组
	int vertexNum;            //顶点数
	int edgeNum;                 //边数
};

无向邻接矩阵的深度优先遍历:

深度优先所搜(DepthFirstSearch)表示用某种规则把一个顶点所连接的后面顶点都遍历一遍,并用一个标识符来表示是否遍历过该节点。特点是不放过任何一个节点。从一个节点出发,遍历所有未访问的节点,结束后如果遍历完后仍有节点未被访问,则换一个节点作为起始点,重复此步骤直至所有节点都被访问。

bool visited[MAXVERTEX];
//深度优先遍历邻接矩阵
void DFSTraverse(MGraph G)
{
	int i;
	for (i = 0; i < G.vertexNum; i++)
	{
		visited[i] = false;
	}
	for (i = 0; i < G.vertexNum; i++)
	{
		if (visited[i] != true)
		{
			DepthFirstSearch(G, i);  //如果该顶点延伸出去所有顶点都访问过,则访问下一个顶点
		}
	}
}

DepthFirstSearch函数用递归实现:

//深度优先搜索邻接矩阵
void DepthFirstSearch(MGraph G,int i)
{
	int j;
	visited[i] = true;      //把该顶点标识符置为true
	cout << G.vexs[i];      //遍历到后打印该顶点
	for (j = 0; j < G.vertexNum; j++)
	{
		if (G.arc[i][j] == 1 && visited[j] != true)
		{
			DepthFirstSearch(G, j);      //递归遍历未访问的节点直到没有
		}
	}
}

无向邻接矩阵的广度优先遍历:

//广度优先遍历邻接矩阵
void BFSTraverse(MGraph G)
{
	int i, j;
	queue<VertexType> q;              //临时队列
	for (i = 0; i < G.vertexNum; i++)
	{
		visited[i] = false;
	}
	for (i = 0; i < G.vertexNum; i++)
	{
		if (!visited[i])
		{
			visited[i] = true;      //标识符设为true
			cout << G.vexs[i];       //遍历到该顶点,打印顶点
			q.push(G.vexs[i]);         //入队
			while (q.empty() != true)     //如果队列不为空
			{
				q.pop();
				for (j = 0; j < G.vertexNum; j++)
				{
					if (G.arc[i][j] == 1 && !visited[j])
					{
						visited[j] = true;
						cout << G.vexs[j];      //遍历并打印
						q.push(G.vexs[j]);
					}
				}
			}
		}
	}
}

无向图的邻接表结构表示:

邻接表类似于链表,存在顶点节点和边节点,用顶点节点的指针指向该顶点所连接的边节点。

//邻接表的结构
typedef struct EdgeNode         //边表节点
{
	int adjvex;               //该邻接点对应的顶点下标
	EdgeType weight;       //顶点到该邻接点的权值
	EdgeNode *Next;       //指向顶点的下一个邻接点
};

typedef struct VertexNode      //顶点表节点
{
	VertexType data;            //顶点节点及信息
	EdgeNode *firstEdge;         //边表头指针,指向顶点的第一个边表
}AdjList[MAXVERTEX];

typedef struct GraphAdjList          //邻接表
{
	AdjList adjList;       //顶电表数组
	int vertexNum;        //顶点数
	int EdgeNum;           //边数
};
无向网图邻接表的创建:

//无向图的邻接表的创建
void CreateALGraph(GraphAdjList *G)
{
	int i, j, k;
	EdgeNode *e;
	cout << "输入顶点数和边数:";
	cin >> G->vertexNum >> G->EdgeNum;    //读入顶点数和边数
	//创建顶点表
	for (i = 0; i < G->vertexNum; i++)
	{
		cin >> G->adjList[i].data;  //读入顶点节点信息
		G->adjList[i].firstEdge = NULL;  //边表初始化为NULL表
	}
	//创建边表
	for (k = 0; k < G->EdgeNum; k++)
	{
		cout << "输入边(vi,vj)上的顶点序号:" << endl;
		cin >> i >> j;    //读入边的顶点序号
		e = new EdgeNode();      //生成边表节点
		//无向图,所以一条边对应两个节点i和j
		//头插法
		e->adjvex = j;       //邻接点下标为j
		e->Next = G->adjList[i].firstEdge;     //e指向G的firstedge
		G->adjList[i].firstEdge = e;            //firstEdge指向该边节点

		e = new EdgeNode();
		e->adjvex = i;
		e->Next = G->adjList[j].firstEdge;
		G->adjList[j].firstEdge = e;
	}
}

无向邻接表的深度优先遍历:

和邻接矩阵的遍历很相似

//深度优先遍历邻接表
void DepthFirstSearchAdjList(GraphAdjList GAL, int i)
{
	EdgeNode *e;
	visited[i] = true;         //标识符设为true
	cout << GAL.adjList[i].data;        //遍历到后打印顶点信息
	e = GAL.adjList[i].firstEdge;
	while (e)
	{
		if (!visited[e->adjvex])
		{
			DepthFirstSearchAdjList(GAL, e->adjvex);   //递归遍历未访问的邻接点
		}
		e = e->Next;
	}
}
//深度优先搜索邻接表
void DFSTraverse(GraphAdjList GAL)
{
	int i;
	for (i = 0; i < GAL.vertexNum; i++)
	{
		visited[i] = false;
	}
	for (i = 0; i < GAL.vertexNum; i++)
	{
		if (!visited[i])
		{
			DepthFirstSearchAdjList(GAL, i);
		}
	}
}

无向邻接表的广度优先遍历:

//广度优先遍历邻接表
void BFSTraverse(GraphAdjList GAL)
{
	int i;
	EdgeNode *p;
	queue<int> q;
	for (i = 0; i < GAL.vertexNum; i++)
	{
		visited[i] = false;
	}
	for (i = 0; i < GAL.vertexNum; i++)
	{
		if (!visited[i])
		{
			visited[i] = true;
			cout << GAL.adjList[i].data<< endl;
			q.push[GAL.adjList[i]];
			while (q.empty() != true)
			{
				q.pop();
				p = GAL.adjList[i].firstEdge;
				while (p)
				{
					if (!visited[p->adjvex])
					{
						visited[p->adjvex] = true;
						cout << GAL.adjList[p->adjvex].data;
						q.push(p->adjvex);
					}
					p = p->Next;
				}
			}
		}
	}
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值