算法导论 第二十二章:图的搜索

图有两种标准的表示方法,即邻接矩阵和邻接表(通常邻接矩阵用于稠密图,邻接表用于稀疏图)。如下:

对于图的搜索有两种方法:深度优先搜索 & 广度优先搜索。

广度优先搜索(Breadth-first search)

广度优先搜索是将已发现和未发现顶点之间的边界沿其广度方向向外扩展。亦即算法首先会发现和s距离为k的所有点,然后才会发现和s距离为k+1的其他顶点。

伪代码:

EG:

运行时间:O(V+E)。

深度优先遍历(Depth-first search)

在深度优先搜索中,对于最新发现的顶点,如果他还有以此为起点而为探测到的变,就沿着此边继续探测下去。当顶点v的所有变都已被探寻后,搜索将回溯到发现顶点v有起始点那条边。

伪代码:

EG:

运行时间:O(V+E).

========================================================================================================================

广度优先搜索完整代码:

#include<iostream>
#include<queue>
#include<climits>
#define UDG 0
#define DG  1

#define WHITE 2
#define GRAY  3
#define BLACK 4

using namespace std;

typedef char vType;
typedef struct gEdge{
	vType adjVertex;   //the adjacency vertex pointed by this edge.
	int weight;        //the weight of this edge
	gEdge *nextEdge;   //Point to the next edge
	}gEdge;

typedef struct gVertex{
	vType key;         // the key of the vertex
	int color;
	int d;
	vType pai;
	gEdge *firstEdge;  // point to the first edge attached to the vertex;
	}gVertex;
typedef struct ALGraph{
	int Vnum;
	int Enum;
	int kind;   //the kind of Graph
	gVertex *HeadVertex;
	}ALGraph;

typedef struct edge{
	vType start;
	vType end;
	}edge;
int Locate(ALGraph &G,vType s)
{//locate the start vertex of one edge in head vertex of the graph
	for(int i=0;i<G.Vnum;i++)
		if(G.HeadVertex[i].key == s)
			return i;
	return -1;
	}
void LinkEdgeToGraph(ALGraph &G, edge e)
{
		gEdge *arc=new gEdge();
		arc->adjVertex=e.end;

		int headV_i=Locate(G,e.start);

		arc->nextEdge=G.HeadVertex[headV_i].firstEdge;
		G.HeadVertex[headV_i].firstEdge = arc;
	}
void Graph_Create(ALGraph &G, vType V[], edge E[])
{
	//init the head vertex
	G.HeadVertex= new gVertex[G.Vnum];
	for(int i=0;i<G.Vnum;i++){
		G.HeadVertex[i].key=V[i];
		G.HeadVertex[i].firstEdge=NULL;
	}  

	//add edge to head vertex in order to create a graph
	if(G.kind == DG) //undirected graph
		for(int i=0; i<G.Enum; i++)
			LinkEdgeToGraph(G,E[i]);
	if(G.kind == UDG) // directed graph
		for(int i=0; i<G.Enum; i++)
		{
			LinkEdgeToGraph(G,E[i]);
			// link again after reversed
			edge temp;
			temp.start = E[i].end;
			temp.end   = E[i].start;
			LinkEdgeToGraph(G,temp);
		 	}
	}
void Graph_Print(ALGraph G)
{
	for(int i=0; i<G.Vnum; i++)
	{
		cout<<G.HeadVertex[i].key;
		gEdge *p = G.HeadVertex[i].firstEdge;
		while(p != NULL)
		{
			cout<<" -->  "<< p->adjVertex;
			p = p->nextEdge;
  			}
		cout<<endl;
  		}
	}
/*
void Q_Print(queue<vType> Q)
{
	cout<<"The Q is:";
	while(!Q.empty())
	{
		cout<<Q.front()<<"  ";
		Q.pop();
		}
	cout<<endl;
	}
*/
vType *ALGraph_BFS(ALGraph &G, vType s)
{
	queue<vType> Q;

	vType *BFSResult=new vType[G.Vnum];

	//label the vertex:the starting vertex becomes GRAY,the others become WHITE...
	for(int i=0; i<G.Vnum; i++)
	{
		gVertex *hVertex=&G.HeadVertex[i];
		hVertex->color = WHITE;
		hVertex->d = INT_MAX;
		hVertex->pai = '0';
		if(hVertex->key == s)
		{
			hVertex->color = GRAY;
			hVertex->d = 0;
			}
		}

	//Clear the Q
	while(!Q.empty())  // making the queue Q empty
		Q.pop();
	Q.push(s);        // s enter queue Q

	//Searching layer by layer
	int r_i=0;
	while(!Q.empty())
	{
		vType u,v;
		u= Q.front();Q.pop();  //delete the front element of the Q

		BFSResult[r_i] = u;    //store the result into Array BFSResult
		r_i++;

		int h_i=Locate(G,u);
		gVertex *hu = &G.HeadVertex[h_i];
		gEdge *p = G.HeadVertex[h_i].firstEdge;
		while(p)
		{
			v = p->adjVertex;

			h_i = Locate(G,v);
			gVertex *hv = &G.HeadVertex[h_i];
			if(hv->color == WHITE)
			{
				hv->color = GRAY;
				hv->d = hv->d+1;
				hv->pai = u;
				Q.push(v);
	 		 	}
			p = p->nextEdge;
	 		}
		hu->color = BLACK;
	 	}
	return BFSResult;
	}
int main()
{
	vType V[]={'s','w','r','v','t','x','u','y'};
	edge  E[]={{'r','v'},{'r','s'},{'s','w'},{'w','t'},{'w','x'},{'t','u'},{'t','x'},{'x','u'},{'x','y'},{'u','y'}};
	ALGraph G;

	G.Vnum=sizeof(V)/sizeof(vType);
	G.Enum=sizeof(E)/sizeof(edge);
	G.kind=UDG;           //the kind of Graph

	Graph_Create(G,V,E);
	cout<<"---------------Create Graph-----------------"<<endl;
	cout<<"The created graph is:"<<endl;
	Graph_Print(G);

	cout<<"---------------BFS Graph--------------------"<<endl;
	cout<<"Please input the starting position:";
	vType s;
	cin>>s;
	vType *BFSResult = new vType[G.Vnum];
	BFSResult=ALGraph_BFS(G,s);
	cout<<"The result of BFS is:"<<endl;
	for(int i=0; i<G.Vnum; i++)
		cout<<BFSResult[i]<<"   ";
	cout<<endl;

	return 0;
	}

运行结果:

深度优先搜索完整代码:

#include<iostream>
#include<iomanip>
using namespace std;

#define UDG 0
#define DG  1

#define WHITE 0
#define GRAY  1
#define BLACK 2  

#define NONE 0
#define TREE 1
#define BACK 2
#define FORWARD 3
#define CROSS 4 

typedef char vType;
typedef struct gEdge{
	vType adjVertex;   //the adjacency vertex pointed by this edge.
	int weight;        //the weight of this edge
	int type;          //the type of edge
	gEdge *nextEdge;   //Point to the next edge
	}gEdge;

typedef struct gVertex{
	vType key;         // the key of the vertex
	int color;
	int d,f;           // the discovered time and the finished time
	vType pai;         // the parent node's key after searching
	gEdge *firstEdge;  // point to the first edge attached to the vertex;
	}gVertex;
typedef struct ALGraph{
	int Vnum;
	int Enum;
	int kind;   //the kind of Graph
	gVertex *HeadVertex;
	}ALGraph;

typedef struct edge{
	vType start;
	vType end;
	}edge;
int Locate(ALGraph &G,vType s)
{//locate the start vertex of one edge in head vertex of the graph
	for(int i=0;i<G.Vnum;i++)
		if(G.HeadVertex[i].key == s)
			return i;
	return -1;
	}
void LinkEdgeToGraph(ALGraph &G, edge e)
{
		gEdge *arc=new gEdge();
		arc->adjVertex=e.end;

		int headV_i=Locate(G,e.start);

		arc->nextEdge=G.HeadVertex[headV_i].firstEdge;
		G.HeadVertex[headV_i].firstEdge = arc;
	}
void Graph_Create(ALGraph &G, vType V[], edge E[])
{
	//init the head vertex
	G.HeadVertex= new gVertex[G.Vnum];
	for(int i=0;i<G.Vnum;i++){
		G.HeadVertex[i].key=V[i];
		G.HeadVertex[i].firstEdge=NULL;
	}   

	//add edge to head vertex in order to create a graph
	if(G.kind == DG) //undirected graph
		for(int i=0; i<G.Enum; i++)
			LinkEdgeToGraph(G,E[i]);
	if(G.kind == UDG) // directed graph
		for(int i=0; i<G.Enum; i++)
		{
			LinkEdgeToGraph(G,E[i]);
			// link again after reversed
			edge temp;
			temp.start = E[i].end;
			temp.end   = E[i].start;
			LinkEdgeToGraph(G,temp);
		 	}
	}
void Graph_Print(ALGraph G)
{
	for(int i=0; i<G.Vnum; i++)
	{
		cout<<G.HeadVertex[i].key;
		gEdge *p = G.HeadVertex[i].firstEdge;
		while(p != NULL)
		{
			cout<<" -->  "<< p->adjVertex;
			p = p->nextEdge;
 		 	}
		cout<<endl;
 		 }
	}

void EdgeType_Print(ALGraph G)
{
	for(int i=0; i<G.Vnum; i++)
	{
		gEdge *p = G.HeadVertex[i].firstEdge;
		while(p)
		{
			cout<<G.HeadVertex[i].key<<"-->"<<p->adjVertex<<":";
			switch(p->type)
			{
				case TREE:
					cout<<"Tree edge"<<endl;
					break;
				case BACK:
					cout<<"Back edge"<<endl;
					break;
				case FORWARD:
					cout<<"Forward edge"<<endl;
					break;
				case CROSS:
					cout<<"Cross edge"<<endl;
					break;
				}
			p = p->nextEdge;
			}
		}
	}

/*--------------------DFS Alogithms-----------------------*/
int time0;
int r_i=0;
void Graph_DFSVisit(ALGraph &G, gVertex *u, vType *r)
{
	time0 = time0 +1;  //white vertex u has just been discovered
	u->d = time0 ;
	u->color = GRAY;

	gEdge *p = u->firstEdge;
	while(p)
	{
		vType v = p->adjVertex;
		int h_i=Locate(G,v);
		gVertex *hv = &G.HeadVertex[h_i];

		//classify the edge and recursive searching
		if( hv->color == WHITE)
	 	{
			hv->pai = u->key;
			Graph_DFSVisit(G,hv,r);
			p->type = TREE;        //Tree edge
			}
		else if(hv->color == GRAY){
			p->type = BACK;        //Back edge
		}
		else if(hv->color == BLACK)
		{
			if(u->d < hv->d)
				p->type = FORWARD; //Forward edge
			else
				p->type = CROSS;  //Cross edge
			}
		p = p->nextEdge;
		}

	u->color = BLACK;  //backen u;it is finished
	r[r_i++]=u->key;   //store the dfs result into array r

	time0 = time0 +1;
	u->f = time0;
}
void ALGraph_DFS(ALGraph &G, vType *result)
{
	//init all the vertex
	gVertex *u;
	for(int i=0; i<G.Vnum; i++)
	{
		u = &G.HeadVertex[i];
		u->color = WHITE;
		u->pai = '0';
		}
	time0 = 0;  //time stamp

	//explore every vertex
	for(int i=0; i<G.Vnum; i++)
	 {
		u = &G.HeadVertex[i];
		if(u->color == WHITE)
			Graph_DFSVisit(G,u,result);
		}
	}
/*----------------------------------------------*/
int main()
{
	vType V[]={'u','x','v','y','w','z'};
	edge  E[]={{'u','x'},{'u','v'},{'x','v'},{'v','y'},{'y','x'},{'w','y'},{'w','z'},{'z','z'}};
	ALGraph G;

	G.Vnum=sizeof(V)/sizeof(vType);
	G.Enum=sizeof(E)/sizeof(edge);
	G.kind=DG;           //the kind of Graph

	Graph_Create(G,V,E);
	cout<<"---------------Create Graph-----------------"<<endl;
	cout<<"The created graph is:"<<endl;
	Graph_Print(G);

	cout<<"---------------DFS Graph--------------------"<<endl;
	vType *DFSResult = new vType[G.Vnum];
	ALGraph_DFS(G,DFSResult);
	cout<<"The result of DFS is:"<<endl;
	for(int i=0; i<G.Vnum; i++)
		cout<<DFSResult[i]<<"   ";
	cout<<endl;
	cout<<"The discovered time and finished time respectivly is:"<<endl;
	for(int i=0; i<G.Vnum; i++)
		cout<<G.HeadVertex[i].key<<setw(4)<<G.HeadVertex[i].d<<setw(4)<<G.HeadVertex[i].f<<endl;
	cout<<"The Edge type information is:"<<endl;
	EdgeType_Print(G);
	cout<<"--------------------------------------------"<<endl;
	return 0;
	}

运行结果:

【注:若有错误,请指正~~~】

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 22:24:29

算法导论 第二十二章:图的搜索的相关文章

算法导论 第二十二章:拓扑排序

拓扑排序(针对有向无回路图DAG)是深度优先搜索的一个应用,其结果图中所有顶点的一个线性排列. 伪代码如下: EG: 拓扑排序完整代码如下: #include<iostream> #include<iomanip> #include<string> #include<algorithm> using namespace std; #define UDG 0 #define DG 1 #define WHITE 0 #define GRAY 1 #define

算法导论第十二章__二叉搜索数

package I第12章__二叉搜索树; //普通二叉树 public class BinaryTree<T> { // -----------------------数据结构--------------------------------- private int height = 0; private Node<T> rootNode; class Node<T> { T t; int key; Node left; Node right; public Node

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)

算法导论 第十二章:二叉查找树(Binary Search Trees)

二叉查找树具有如下性质: x是二叉查找树中的一个节点,如果y是x左子树中的一个节点,则y.key ≤ x.key ; 如果 y 是 x 右子树中的一个节点,则 x.key ≥ y.key. 在二叉树上执行的基本操作的时间与树的高度成正比.当这棵树是完全二叉树时,这些操作的最坏情况运行时间为Θ(lgn);如果该树是含n个节点的线性链,则这些操作的最坏情况的运行时间为Θ(n).我们可以通过随机构造二叉查找树(期望高度:E(h)=O(lgn)),从而使得在这种树上基本动态集操作的平均时间为Θ(lgn)

第二十二章 TCP/IP层的实现

                      第二十二章    TCP/IP层的实现        我比较喜欢先难后易,如果把GPU显示管理.和网络管理拿下后:我会从头整理.改写一遍APO操作系统.这样,就会形成APO操作系统的锥形.也获得了全局观.内核CPU线路.和用户CPU线路,你可以将它们看成是独立的2个32位CPU核:内核CPU主要任务是实时处理.硬件中断,256个实时线程包含了一些中断程序的后半部.用户CPU主要是动态优先级进程.线程调度,各种应用程序的运行:2个核之间是通过消息交互.句

Gradle 1.12用户指南翻译——第二十二章. 标准的 Gradle 插件

其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,兼容

第二十二章 Linux文件比较,文本文件的交集、差集与求差:comm命令

第二十二章 Linux文件比较,文本文件的交集.差集与求差:comm命令 名词解释 comm 命令 可以用于两个文件之间的比较,它有一些选项可以用来调整输出,以便执行交集.求差.差集操作. 交集:打印两个文件所共有的行 求差:打印出指定文件所包含的其不相同的行. 差集:打印出包含在一个文件中,但不包含在其他指定文件中的行. 语法 comm(选项)(参数) 选项 -1 :不显示在第一个文件出现的内容: -2 :不显示在第二个文件中出现的内容: -3 :不显示同时在两个文件中都出现的内容. ? 参数

“全栈2019”Java第二十二章:控制流程语句中的决策语句if-else

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第二十二章:控制流程语句中的决策语句if-else 下一章 "全栈2019"Java第二十三章:流程控制语句中决策语句switch上篇 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf

20190925 On Java8 第二十二章 枚举

第二十二章 枚举 基本 enum 特性 创建 enum 时,编译器会为你生成一个相关的类,这个类继承自 Java.lang.Enum. valueOf() 是在 Enum 中定义的 static 方法,它根据给定的名字返回相应的 enum 实例,如果不存在给定名字的实例,将会抛出异常. 将静态类型导入用于 enum 使用 static import 能够将 enum 实例的标识符带入当前的命名空间,所以无需再用 enum 类型来修饰 enum 实例. 方法添加 除了不能继承自一个 enum 之外