图的广度优先搜索 深度优先搜索 最短路径 拓扑排序(邻接链表表示)

图的结点结构是:

    //定义结点颜色种类,辅助图的遍历,
//WHRITE:未访问 GRAY:开始访问,邻接点还没有访问完 BLACK:访问完成
enum ColorType {WHRITE, GRAY, BLACK};

struct VNode           //头结点
{
VertexType data;    //顶点信息
ArcNode *firstarc;  //指向第一条依附于该顶点的弧的指针
ColorType color;
VNode *p;
int begin;          //BFS中记录从原结点到该结点的最短距离,DFS中记录开始访问时间
int end;            //DFS中记录访问结束时间
};

BFS中的begin 用来记录每个结点距离源结点的距离,BFS能够找出给定源节点 s到所有可以到达的结点之间的距离,且是最短距离。

借助一个队列记录依次的遍历顺序,没有访问时进队,出队时依次访问该结点的邻接点,一直循环知道队列为空。

BFS运行时间分析:每个结点进队出队一次,所以队列操作时间是O(E),当一个结点出队时对其邻接结点访问,总的邻接表长度为O(E)长度,所以运行时间为O(V+E)


对于图G = (V,E)和源节点s,G的前驱子图为Gp = (Vp, Ep), 

如果Vp是由源节点s可以到达的结点组成,并且对于所有的v 属于 Vp,子图Gp包含一条从源节点s到结点v的唯一简单路径,且该路径也是图G中从源节点s到结点v的一条最短理解,则前驱子图是一棵广度优先树。广度优先树为树,所以有Ep = Vp -1 ;

定理 22.6 当运行在一个有向或无向图G = (V,E)上时,BFS过程中所建造出来的p属性使得前驱字符Gp = (Vp, Ep)成为一棵广度优先树。

printPath打印从源节点到其他结点的最短路径,该算法用递归实现,其实是根据p属性构造出来的广度优先搜索树,根据p走一条结点到根结点的路径,递归到源结点,然后在退出时依次打印路径上的结点,这条路径即为最短路径。

DFS为深度优先,深度优先搜索的前驱子图可能有多棵树组成,因为搜索可能从多个源节点重复进行。深度优先搜索的前驱子图形成一个由多棵深度优先树构成的深度优先深林,

DFS在每个结点上盖一个时间戳,v.begin 记录 结点v第一次被发现的时间(涂上灰色的时间), v.end记录的是搜索完成对v的邻接表扫描的时间(涂上黑色的时候),这些时间提供了图结构的重要信息。用一个静态变量time记录时间。

DFS时间分析:对于每个白色节点调用一次DFSVisit,所以共调用O(V)次,算法中的循环是遍历每个结点的邻接点,总共为O(E),所以总的时间为O(V+E)


可以利用DFS对有向无环图进行拓扑排序,针对这个拓扑排序是所有节点按照其完成时间的逆序排成的顺序。

记录方法类中 定义一个记录拓扑顺序的列表,在DFS中,当每个结点访问完成(即变为黑色后),将其插入到列表的最前端,

算法完成时,则将结点按照完成时间的逆序放入到了链表中。


代码中的三个图为:

图1:算法导论(第三版)345页图(无向图)


图2:算法导论(第三版)351页图(有向带环图)


图3:数据结构与算法分析 251页图(有向无环图)


以下为代码及注释:

algraph.h定义这个图的结构和所有的方法, main.cpp中为主程序,

/************************************************************************/
/*   ALGraph.h: 图的构造和算法
     Date:2013/12/27         */
/************************************************************************/

#ifndef ALGRAPH_H
#define ALGRAPH_H

#include <vector>
#include <iostream>
#include <queue>
#include <list>
#include <algorithm>
using namespace std;

template <typename VertexType>
class ALGraph
{
public:
	//构造函数
	ALGraph(int verNum) : vexnum(verNum), arcnum(0)
	{
		for (int i = 0; i < MAX_VERTEX_NUM; i++)
		{
			vertices[i].firstarc = NULL;
			vertices[i].color = WHRITE;
			vertices[i].begin = 0;
			vertices[i].end = 0;
			vertices[i].p = NULL;
		}
	}

	//构造图
	virtual void Create()
	{
		InitVertics();
	}

	//构造算法导论345图
	void CreateUDG1()
	{
		for (int i = 0; i < vexnum; i++)
		{
			vertices[i].data = i + 'r';
		}
		insertArc(0, 1);
		insertArc(0, 4);
		insertArc(1, 5);
		insertArc(2, 3);
		insertArc(2, 5);
		insertArc(2, 6);
		insertArc(3, 6);
		insertArc(3, 7);
		insertArc(5, 6);
		insertArc(6, 7);

		insertArc(1, 0);
		insertArc(4, 0);
		insertArc(5, 1);
		insertArc(3, 2);
		insertArc(5, 2);
		insertArc(6, 2);
		insertArc(6, 3);
		insertArc(7, 3);
		insertArc(6, 5);
		insertArc(7, 6);
	}

	//构造算法导论351图
	void CreateDG1()
	{
		for (int i = 0; i < vexnum; i++)
		{
			vertices[i].data = 'u' + i;
		}
		insertArc(0, 1);
		insertArc(0, 3);
		insertArc(1, 4);
		insertArc(2, 4);
		insertArc(2, 5);
		insertArc(3, 1);
		insertArc(4, 3);
		insertArc(5, 5);
	}

	//构造数据结构与算法分析251图,有向无环图
	void CreateDG2()
	{
		for (int i = 0; i < vexnum; i++)
		{
			vertices[i].data = 1 + i;
		}
		insertArc(0, 1);
		insertArc(0, 2);
		insertArc(0, 3);
		insertArc(1, 3);
		insertArc(1, 4);
		insertArc(2, 5);
		insertArc(3, 2);
		insertArc(3, 5);
		insertArc(3, 6);
		insertArc(4, 3);
		insertArc(4, 6);
		insertArc(6, 5);
	}

	//BFS辅助程序
	void BFSGraph()
	{
		//结点数组初始化
		for (int i = 0; i < vexnum; i++)
		{
			vertices[i].color = WHRITE;
			vertices[i].p = NULL;
			vertices[i].begin = 0;
			vertices[i].end = 0;
		}
		//源节点为第一个结点
        cout << "图的广度优先搜索:" << endl;
		for (int i = 0; i < vexnum; i++)
		{
			if (vertices[i].color == WHRITE)
				__BFSGraph(&vertices[i]);
		}	
		cout << endl;
	}

	//打印最短路径辅助程序,BFS可以计算出从指定源节点到其可达结点的最短路径
	void printPath()
	{
		int di;
		cout << "请输入目的结点的序号:";
        cin >> di;
		__printPath(&vertices[0], &vertices[di-1]);
		cout << endl;
	}

	//全局变量time 重置为0
	void resetTime()
	{
		time = 0;
	}

	//DFS 辅助程序
	void DFSGraph()
	{
		resetTime();
		//结点数组初始化
		for (int i = 0; i < vexnum; i++)
		{
			vertices[i].color = WHRITE;
			vertices[i].p = NULL;
			vertices[i].begin = 0;
			vertices[i].end = 0;
		}
		cout << "图的深度优先搜素:" << endl;
               //全局时间计数器复位
		for (int i = 0; i < vexnum; i++)
		{
			if (vertices[i].color == WHRITE)
	           DFSVisit(vertices[i]);
		}
		cout << endl;
	}

	//打印拓扑排序列表
	void printTopList()
	{
		cout << "图的拓扑排序为:" << endl;
        copy(toplist.begin(), toplist.end(), ostream_iterator<VertexType>(cout, " "));
		cout << endl;
	}
	
	//打印邻接链表
	void displayGraph()
	{
		for (int i = 0; i < vexnum; i++)
		{
			cout << "第" << i+1 << "个顶点是:" << vertices[i].data
				<< " 邻接表为: ";
			ArcNode *arcNode = vertices[i].firstarc;
			while (arcNode != NULL)
			{
				cout << " -> " << vertices[arcNode->adjvex].data;
					/*<< "(" << arcNode->weight << ")";*/
				arcNode = arcNode->nextarc;
			}
			cout << endl;
		}
	}

protected:
	//初始化邻接链表的表头数组
	void InitVertics()
	{
		cout << "请输入每个顶点的关键字:" << endl;
		VertexType val;
		for (int i = 0; i < vexnum; i++)
		{
			cin >> val;
			vertices[i].data = val;
		}
	}

	//插入一个表结点
	void insertArc(int vHead, int vTail)
	{
		//构造一个表结点
		ArcNode *newArcNode = new ArcNode;
		newArcNode->adjvex = vTail;
		newArcNode->nextarc = NULL;

		//arcNode 是vertics[vHead]的邻接表
		ArcNode *arcNode = vertices[vHead].firstarc;
		if (arcNode == NULL)
			vertices[vHead].firstarc = newArcNode;
		else
		{
			while (arcNode->nextarc != NULL)
			{
				arcNode = arcNode->nextarc;		
			}
			arcNode->nextarc = newArcNode;
		}
		arcnum++;
	}

private:
	static int time;       //DFS中记录时间
	//static const int数据成员可以在类里定义
	static const int MAX_VERTEX_NUM = 20;  //最大顶点个数

	struct ArcNode          //表结点
	{
		int adjvex;        //该弧所指向的顶点的位置
		ArcNode *nextarc;  //指向下一条弧的指针
	};

	//定义结点颜色种类,辅助图的遍历,
	//WHRITE:未访问 GRAY:开始访问,邻接点还没有访问完 BLACK:访问完成
	enum ColorType {WHRITE, GRAY, BLACK};

	struct VNode           //头结点
	{
		VertexType data;    //顶点信息
		ArcNode *firstarc;  //指向第一条依附于该顶点的弧的指针
		ColorType color;
		VNode *p;
		int begin;          //BFS中记录从原结点到该结点的最短距离,DFS中记录开始访问时间
		int end;            //DFS中记录访问结束时间
	};

	VNode vertices[MAX_VERTEX_NUM];
	int vexnum;             //图的当前顶点数
	int arcnum;             //图的弧数
	list<VertexType> toplist;     //topSort数组,存放拓扑排序序列

	//BFS主程序
	void __BFSGraph(VNode *node)
	{
		node->color = GRAY;
		node->begin = 0;
		node->p = NULL;

		queue<VNode *> que;
		que.push(node);

		while (que.empty() == false)
		{
			VNode *nd = que.front();
			que.pop();
			cout << nd->data << "->";
			ArcNode *lnd = nd->firstarc;
			while (lnd != NULL)
			{
				VNode *nnd = &vertices[lnd->adjvex];
				if (nnd->color == WHRITE)
				{
					nnd->color = GRAY;
					nnd->begin = nd->begin + 1;
					nnd->p = nd;
					que.push(nnd);
				}
				lnd = lnd->nextarc;
			}
			nd->color = BLACK;
		}
	}

	//打印从s到v的最短路径
	void __printPath(VNode *s, VNode *v)
	{
		if (v == s)
		    cout << s->data << " ";
		else if (v->p == NULL)
			cout << "no path from " << s->data << " to " << v->data << endl;
		else 
		{
			__printPath(s, v->p);
			cout << v->data << " ";
		}
	}

	//DFS主程序
	void DFSVisit(VNode &node)
	{
		time++;
		node.begin = time;
		node.color = GRAY;
		cout << node.data << " begin-time: " << node.begin << endl; 

		ArcNode *lnode = node.firstarc;
		while (lnode != NULL)
		{
			VNode &nd = vertices[lnode->adjvex];   //依次访问每个邻接点
			if (nd.color == WHRITE)     
			{
				nd.p = &node;
				DFSVisit(nd);
			}
			//当该邻接点已经访问过,则指向下一个邻接点
			if (nd.color == BLACK)
				lnode = lnode->nextarc;
			else
				break;			
		}
		node.color = BLACK;
		time++;
		node.end = time;	
		//cout << node.data /*<< " begin-time: " << node.begin */
		//	<< " end-time: " << node.end << endl; 
		//拓扑排序是结点的完成时间的逆序
		toplist.push_front(node.data);     //当每个结点访问完,则插入到链表头部
	}
};

#endif

/************************************************************************/
/*   main.cpp: 主函数
     Date:2013/12/27         */
/************************************************************************/

#include "ALGraph.h"

int ALGraph<char>::time = 0;
int ALGraph<int>::time = 0;

int main()
{
	cout << "------------------------------------------------" << endl;
	cout << "构造无向图:算法导论(第三版)345页图:" << endl;
	ALGraph<char> udgGraph(8);
	udgGraph.CreateUDG1();
	udgGraph.displayGraph();
	udgGraph.BFSGraph();
	udgGraph.printPath();
	udgGraph.DFSGraph();

	cout << "------------------------------------------------" << endl;
	cout << "构造有向图:算法导论(第三版)351页图:" << endl;
	ALGraph<char> dgGraph(6);
	dgGraph.CreateDG1();
	dgGraph.displayGraph();
	dgGraph.BFSGraph();
	dgGraph.printPath();
	dgGraph.DFSGraph();

	cout << "------------------------------------------------" << endl;
	cout << "构造有向无环图:构造数据结构与算法分析251图:" << endl;
	ALGraph<int> dgGraph1(7);
	dgGraph1.CreateDG2();
	dgGraph1.displayGraph();
	dgGraph1.BFSGraph();
	dgGraph1.DFSGraph();
	dgGraph1.printTopList();

	system("pause");
	return 0;
}


附上算法导论书上BFS,DFS运行时图的变化:


运行结果为:




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值