图的遍历
概念
深度优先遍历
DFS(Depth-First-Search,深度优先搜索)算法的具体做法是:从某个点一直往深处走,走到不能往下走之后,就回退到上一步,直到找到解或把所有点走完。
在实现这一个依次的访问顺序时,操作动作存储与数据结构(栈)的思想及其相似,同时也由于栈的性质,我们可以通过递归来简化栈的创建,因此DFS算法的两种做法分别时利用栈或者递归实现。
算法步骤(递归或栈实现)
a)访问指定起始地点。
b)若当前访问顶点的邻接顶点有未被访问的顶点,就任选一个访问。如果没有就回退到最近访问的顶点,直到与起始顶点相通的所有点被遍历完。
c)若途中还有顶点未被访问,则再选一个点作为起始顶点,并重复前面的步骤。
2访问完后在2的没有被访问的邻接点中选一个(而2号的邻接点存放在邻接矩阵中行下标为2的这行然后顺序去找前提值必须1网则是权值(非0);没有访问过<看visit数组对应的值是不是0>)2–》1,访问1之后修改visited[1]=1–>找1没有被访问过的邻接点(行下标为1个这行依次判断<第一个不行值为0没有边看下一个值是1visited数组值为1访问过了>继续看下一个经过判断3号可以的)1–》3 访问3之后修改visited[3]=1 …3–》5,(5第一个邻接点2访问过了第二个邻接点3也访问过了)–?回退回3–》回退回1–》4–》6–》退到4–》退回1–》退回2(退回起点)访问完毕
DFS访问结果:2–>1–>3–>5–>4–>6(存储结构确定-结果确定)
实现
DFS算法的相关模板如下:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据需求添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝,去除一些不需要访问的场景,不一定i俺家
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
对于图论而言(代码节选,仅做参考,最主要还请记忆上面的模板那代码):
//从pos点开始,深度遍历无向图
//pos表示当前结点,G表示图,visited[]数组用来表示该节点是否已经访问
void DFS(int pos,pGraph G,int visited[30]){
node p;
printf("%d ",pos);//打印深度遍历的点
visited[pos]=1;//标记为以访问过
p=G->vertice[pos].firstarc;//将当前点的第一个指针赋值给p
//是否存在邻接点
while(p!=NULL) {
//判断该邻接点是否被遍历过
if(visited[p->adjvex]==0){
DFS(p->adjvex,G,visited);
}
p=p->next;//后移一位,为之后是否有邻接点做准备
}
}
广度优先遍历
BFS算法和核心思路就是:从某个点一直把其邻接点走完,然后任选一个邻接点把与之邻接的未被遍历的点走完,如此反复走完所有结点。类似于树的层序遍历。
BFS的核心就是要把当前在哪作为一个状态存储,并将这个状态交给队列进行入队操作,故而,
算法步骤(用队列实现)
a) 访问指定起始点。
b) 访问当前顶点的邻接顶点有未被访问的顶点,并将之放入队列中。
c) 删除队列的队首节点。访问当前队列的队首,前面的步骤。直到队列为空。
d) 若若途中还有顶点未被访问,则再选一个点作为起始顶点。重复前面的步骤。(针对非连通图)。
和树的层次遍历类似(用队列根结点出队将它的左右孩子入队…)设起点为V1,在数组中的0号位置0入队–》V1访问完后出队还要修改visited[1]=1把V1的没有访问过的邻接点入队将1和2入队–》访问完V2把V2出队修改visited[2]=1把V2的没有访问过的邻接点入队(3和4)–》V3(当前队头)访问完出队修改visited[1]=1…(队为空visit数组均为1遍历结束)
算法实现
BFS的模板代码如下:
/**
* 返回合适的检索数据
*/
int BFS(Node root, Node target)
{
Queue<Node> queue; //创建队列
int step = 0; // 当前队列的步骤点
// initialize
add root to queue;
// BFS
while (queue is not empty)
{
step = step + 1;
//步数逐渐增加
int size = queue.size();
for (int i = 0; i < size; ++i)
{
Node cur = the first node in queue;
if cur is target
return step - 1;
for (Node next : the neighbors of cur)
{//这里常用一个二维方向数组实现
add next to queue;
}
remove the first node from queue;
}
}
return -1; //出错返回值
}
同样提供一份BFS的图论算法节选,代码最核心还是取记忆BFS的模板并根据实际情况的灵活使用,故以下代码仅提供参考
void BFSL(int pos,pGraph G,int visited[30])//从pos点开始进行广度优先遍历无向图
{
int queue[G->Vnum];//队列辅助BFS遍历
int head=0,tail=0;//队头、队尾指针
Arcnode* p;
queue[tail]=pos;
visited[pos]=1;//标记遍历过
tail++;
while(head!=tail)
{
pos=queue[head];//出队操作
head++;
printf("%d ",pos);
p=G->vertice[pos].firstarc;
while(p!=NULL)
{
if(visited[p->adjvex]==0)//判断是否遍历过
{
queue[tail]=p->adjvex;//入队操作
visited[p->adjvex]=1;//标记遍历过
tail++;
}
p=p->next;
}
}
}