算法学习-栈与深度优先搜索(DFS)

一、概念

深度优先搜索(Depth First Search)主要是用来遍历存储结构的一种算法,它既使用于无向图,也适用于有向图。

图的遍历主要是逐个访问图中的每一个顶点,并且还要确保,图的所有顶点都只被访问一次。

二、具体步骤

深度优先搜索算法的原则主要就是从图中的某个顶点出发,不停的寻找相邻的、尚未访问的顶点:

        1. 如果找到多个,则任选一个顶点,然后继续从该顶点出发。

        2. 如果一个都没有找到,则回退之前访问过的顶点,看看是否存在漏掉的顶点。

        3. 只到从V顶点出发,回退到V顶点。再向上面一样重复查找是否存在未访问过的顶点,不存在的话则算法结束。

通常情况下,深度优先搜索算法访问图中顶点的顺序是不唯一的,即顶点的访问序列可能有很多种(≥1)

三、用深度优先搜索解迷宫案例

其实通过具体步骤的分析可以看出,在深度优先搜索的时候,可以用一个来维护当前结点。

首先给定一个二维数组来表示一个迷宫,其中1表示墙壁,0表示可以走的路,规定只能横着走和竖着走,不能斜着走,要求通过写一个程序,找出从左上角到右下角中的一条路线。

int maze[5][5] = {
    0,1,0,0,0,
    0,1,0,1,0,
    0,0,0,0,0,
    0,1,1,1,0,
    0,0,0,1,0,
};

代码实现:

​
/*深度优先搜索遍历算法解决迷宫问题*/
#include<stdio.h>

#define MAX_ROW 5
#define MAX_COL 5

/*
  堆栈中的元素是结构体类型
  主要用来表示迷宫中的一个点x和y的坐标
*/
struct point{int row,col;}stack[512];
/*记录栈中元素的个数*/
int top = 0;
/*入栈操作*/
void push(struct point p)
{
	stack[top++] = p;
}
/*取栈顶元素*/
struct point pop(void)
{
	return stack[--top];
}
/*判断栈是否为空*/
int is_empty(void)
{
	return top == 0;
}
/*
迷宫:走过的路通过2标识,防止重复走。
最后找到终点时就根据predecessor数组保存的路线打印
*/
int maze[MAX_ROW][MAX_COL] =  
{
	0,1,0,0,0,
	0,1,0,1,0,
	0,0,0,0,0,
	0,1,1,1,0,
	0,0,0,1,0,

};
/*打印*/
void print_maze(void)
{
	int i,j;
	for(i=0; i<MAX_ROW; i++){
		for(j=0; j<MAX_COL; j++){
			printf("%d ",maze[i][j]);		
		}
		putchar('\n');	
	}
	printf("************\n");
}
/*
  记录前趋点,表示从哪走到当前点
  predecessor[4][4]是坐标为(3,4)的点,就表示从(3,4)->(4,4)
*/
struct point predecessor[MAX_ROW][MAX_COL]={
    {
   
   {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {
   
   {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {
   
   {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {
   
   {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {
   
   {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
};
/*
  记录顶点移动时候的信息
*/
void visit(int row,int col,struct point pre)
{
	struct point visit_point = {row,col};//保存当前顶点的信息
	maze[row][col] = 2;//标记访问过的顶点
	predecessor[row][col] = pre;//保存之前顶点信息
	push(visit_point);//压栈
}

int main(void)
{
	/*初始化起始位置*/
	struct point p = {0,0};
	maze[p.row][p.col] = 2;
	push(p);
	/*栈非空*/
	while(!is_empty()){
        /*从栈顶弹出一个点p*/
		p=pop();
		/*如果这个顶点是终点*/
		if(p.row == MAX_ROW-1 && p.col == MAX_COL-1)
			break;
		/*向右移动*/
		if(p.col+1 < MAX_COL && maze[p.row][p.col+1]==0)
			visit(p.row,p.col+1,p);
		/*向下移动*/
		if(p.row+1 < MAX_ROW && maze[p.row+1][p.col]==0)
			visit(p.row+1,p.col,p);
		/*向左移动*/
		if(p.col-1 >= 0 && maze[p.row][p.col-1]==0)
			visit(p.row,p.col-1,p);
		/*向上移动*/
		if(p.row-1 >= 0 && maze[p.row-1][p.col]==0)
			visit(p.row-1,p.col,p);
	}
	if(p.row == MAX_ROW-1 && p.col == MAX_COL-1){
		printf("(%d,%d)\n",p.row,p.col);
		while(predecessor[p.row][p.col].row != -1){
			p = predecessor[p.row][p.col];
            		printf("(%d,%d)\n", p.row, p.col);
		}
	}else{
		
		printf("No path!\n");	
	}
	return 0;
}

代码结果:

代码分析流程:

在深度优先搜索的过程中,借助了栈的方法达到回溯的要求。并通过配合标记2防止重复路线的访问。最后通过遍历predecessor来找出最后访问出来的路线。

猜你喜欢

转载自blog.csdn.net/Forever_change/article/details/133858854