什么是深度优先搜索呢?
就是从一个切入点 切入,然后遇到符合条件的就进入递归,好比一个人走迷宫,找到路可以走就一直深入往下走,走啊走,走到死路的时候就回退到刚才的岔路口,走另外一条路,这样,人终会走出迷宫(不过走迷宫可以不走完,而这个图的遍历是要走完全部的)。
图的深度优先搜索的方法和过程举例:
比如说是下面这个图,如果从A开始出发的话
那么过程就如图所示:A ->D ->F ->H ->I ->C ->B ->E ->G
为什么会这样遍历呢? 这就和刚才的走迷宫一样,比如说,人从A 走进去,发现A是一个"岔路口"既:D,C,B都可以走,但这个人选这走D(这个跟邻接表的结构和代码有关),然后他走到了D发现D只有F可以走,然后走到了F ,F 走到H,再走到I,然后发现,I之后就没有路可以走了,就往回走(回退),回到H,发现H没有《未走过的路》可以走,走回到F,发现F也没有《未走过的路》可以走,就继续回去,回到D,发现也没有《未走过的路》,在回去A,诶?岔路口有《未走过的路》可以走啊,于是从A走到C,C 之后就没有路可以接着往下走了,就回到A,发现A那个岔路口还有B可以走!然后走 B->E->G,G同理I 时的操作,最后回到A那里,然后A发现自己也把所有的路都走完了,然后递归结束,整个图的比遍历就结束。
什么是广度优先搜索呢?
所谓广度优先搜索,就好比是在湖里滴了一滴水滴,然后,水面上产生了一层又一层的水纹,水纹所及之处,就是遍历过的地方…
刚才例图的广度优先遍历如下图所示
那如何实现这样的遍历方法呢?那就要需要用一个特殊的数据结构:队列(先进先出)
假如我们从A出发,A先进队列,输出A,然后标记A已经访问过,然后找和A相连的其他顶点,它们分别是D,C,B ,好,先让A出队列,然后让它们(D,C,B)都分别进入队列,此时队列里的元素为D,C,B,接着从队列中取出一个元素重复刚才类似的操作,即取出D然后D连接的那个元素进入队列,即F进入队列,输出D,标记D,然后弹出D,此时队列元素为:C,B,F,然后取C重复刚才的操作,却发现C并没有相连却没有标记为遍历过的元素,因此只需要输出C,标记C,再从队列里弹出C,接着队列里的元素只剩B,F,然后重复刚才的操作,取出B,然后发现与B连接的元素为E,让E进入队列,输出B,标记B,再从队列里弹出B,此时队列里的元素为:F,E…
接下来简略过程:
输出F,标记F,弹出F,H进队列,队列里元素为E,H
输出E,标记E,弹出E,G进队列,队列里元素为H,G
输出H,标记H,弹出H,I进队列,队列里元素为G,I
G和I同理C,分别按顺序输出G,I
因此,整个遍历结果的顺序就为:A D C B F E H G I
什么是连通分量(连通分支)?
就是说一个图是由多个连通图组成的
比如说,下面这个图就是由两个连通分量组成的
如果我们从A开始进行深度优先遍历,那么先走A,再走D,再走E,回退到A(先回退到D),再走B,因为E已经遍历过,所以这个深度优先搜索就结束了,那么,由此我们可以知道,深度优先搜索结束了几次,就是图中连通分量有多少个,啊,那么,这个代码就非常容易实现啦,只需要用个FOR循环,配合个标记访问的数组,FOR循环执行次数为顶点个数,那么,比如说,我们从A出发,那么在一次深度优先遍历中,会输出A D E B,因此,这个搜索过程下来,已标记访问过的顶点就已经有A D E B 了,那么,FOR循环将会跳过 这几个顶点,直接从某一个未访问过的顶点 开始下一次深度优先遍历,然后对于这个图来说,第二次深度优先遍历就可以访问完所有顶点,然后结束第二次深度优先遍历,因此可以得到连通分量为2(连通分量初始为0,然后每次深度优先遍历完成时+1)
附上这三个功能实现的代码(因为是基于之前代码实现的,因此会有一些多出来的代码,见谅见谅)
#include<iostream>
#include<cstring>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int maxWeight = RAND_MAX; //无穷大的值
const int DefaultVertices = 30; //最大顶点数不妨设为30
template <class T, class E>
class Graph {
protected:
int maxVertices=10;//图中最大顶点数
int numVertices=0;//图中当前顶点数
int numEdges=0;//图中当前边数
bool direction=false;//图中边的是否有方向
bool withCost=false;//图中的边是否带权
//返回顶点名vertex的序号(从0开始)
int getVertexPos (T vertex);
public:
void DFS (const T& v)
{
}
void BFS (const T& v)
{
}
Graph(int sz , bool direct, bool cost); //构造函数
~Graph()//析构函数
{
}
//析构函数
bool GraphEmpty () const //判图是否为空,因为不需要修改,因此设置为常成员函数
{
return numEdges == 0;
}
bool GraphFull() const; //判图是否为满
//返回图中当前顶点数
int NumberOfVertices ()
{
return numVertices;
}
//返回图中当前边数
int NumberOfEdges ()
{
return numEdges;
}
//取回序号为 i 的顶点值(顶点名)
virtual T getValue (int i){
}
//取顶点序号为v1,v2的边上权值
virtual E getWeight (int v1, int v2){
}
//取顶点 v 的第一个邻接顶点序号
virtual int getFirstNeighbor (int v){
}
//返回顶点 v 和邻接顶点 w 的下一个邻接顶点序号
virtual int getNextNeighbor (int v, int w){
}
//插入新顶点, 点名为vertex
virtual bool insertVertex (const T vertex){
}
//插入新边(v1,v2), 权值cost
virtual bool insertEdge (T v1, T v2, E cost){
}
//删除名为 v 的顶点和所有与它相关联的边
virtual bool removeVertex (T v){
}
//在图中删除边(v1,v2)
virtual bool removeEdge (T v1, T v2){
}
};
template<class T , class E>
Graph<T,E>::Graph (int sz , bool direct, bool cost)
{
sz = DefaultVertices, direct=false, cost=false;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
template <class T, class E> //
class Edge_Vertices {
//边结点的类定义
public:
int dest; //边的邻接(终)点序号
E cost; //边上的权值
Edge_Vertices<T, E>* link;//下一个连接顶点
Edge_Vertices (int num=0, Edge_Vertices<T, E>* next=NULL, E weight=NULL) //构造函数
: dest (num), link (next), cost (weight) {
}
bool operator != (Edge_Vertices<T, E>& R) const
{
return dest != R.dest; } //重载!=运算符,判边不等
};
template <class T, class E>
class Vertex {
//顶点的类定义
public:
T data; //源顶点的名字(数据)
Edge_Vertices<T, E>* next=NULL; //next指针用来连接顶点
};
//邻接表图的类定义继承图类
template <class T, class E>
class Graphlnk : public Graph<T, E>{
public:
void Enter (void); //输入图中顶点和边信息
void Print (void); //输出图中顶点和边信息
//源顶点表 (各边链表的源顶点)
Vertex<T, E>* NodeTable;
//返回名为vertex的顶点在图中的序号(从0开始),
//若未找到,则返回-1
int getVertexPos (const T vertx) //找到目标顶点所在的序号 期中 vertx 参数为string 类型
{
for (int i = 0; i < this->numVertices; i++)
if (NodeTable[i].data == vertx) return i;
return -1;
} //构造函数
Graphlnk( int sz=DefaultVertices, bool direct=false, bool cost=false );
~Graphlnk(); //析构函数
T getValue (int i)