目录

前言:

深度优先遍历(DFS)

FIRST 简单分析

一:全排列问题

补优化算法:


前言:

深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath First Search),能够解决寻路(走迷宫)和搜索引擎等方面的问题,因此在平时面试题中经常出现。

深度优先遍历(DFS)

这个其实在我上一篇的二叉树遍历中就已经提到了相关的知识,其实可以这样理解二叉树的前序遍历和中序遍历还有后序遍历都属于深度优先遍历的一种。

而深度优先遍历又分为主要两种理解方式:递归理解和栈运算。

FIRST 简单分析

其实递归运算归根结底也是属于栈的退栈和入栈运算

我们可以简单的来叙述看一下

java 深度优先遍历 递归 深度优先遍历栈实现_面试

      我们可以简单的理解为一个入栈操作和二叉树的一个遍历的一个相结合,有ABC三个数,我们效仿层次遍历的方法去填入每一层,当然我们每一层填入的数据,必须是上一层没有用到过的,比如刚开始时可以选择先放入A,B,C三种可能,选定好根节点,那么他的子节点有两种可能,其次选好子节点以后,那么根节点也同时确定下来了。然后遍历一下输出即可。

那么我们在进行书写dfs算法的时候需要那几个变量呢

dfs(char/int a[],biaozhi[],step);

数组a[]是用来存储所有的数据,数组biaozhi[]长度和数组a一致,起到的作用是标注在层遍历时有哪些数据是使用了的,那些是没使用的。最后的step的值等于层数+1。(为什么这里使用的step是层数加一,因为是用来判断是否已经完全放入数据,看完下面两个例子可能会更加明白)。

那么模板就变得非常清晰

void  dfs(int step)
{ 
    if(step==n+1)
    {
        for(i=1;i<=n;i++)
        {
        printf("%d",a[n])
        }
    return;
    }
//第一部分截至条件(也就是我们常说的递归出口)
//第二部分遍历候选节点
    for(int i=1;i<=n;i++)
    {
	 if(biaozhi[i]==0)//筛选是否使用过
        {   
	    a[step]=i;//
	    biaozhi[i]=1;//
		dfs(step+1);
	    //注意这里是自己调用自己		
	    biaozhi[i]=0;
		}
	}
}

递归运算我简单举两个例子来简单分析一下。

一:全排列问题

用1~9这9个自然数随机挑选出三个数进行组合成一个三位数,输出任意两三位数的和等于另一个三位数的所有可能性。

#include<stdio.h>
int a[10],biaozhi[10],total;
//这里还有需要注意的地方C语言全局变量默认为0

void  dfs(int step){ 
	int i;
	if(step==10)//判断数字是否已全部放入
       { 
		if(a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]==a[7]*100+a[8]*10+a[9])
            {
			total++;//记录成功数
			printf("%d%d%d+%d%%d=%d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
		    } 	
	        return ;//返回上一级dfs
        }		
	 for(int i=1;i<=9;i++)//
     {
	 if(biaozhi[i]==0)
         {  
		    a[step]=i;//
			biaozhi[i]=1;/	
            //完成数字分配
			dfs(step+1);
			/*注意这里是自己调用自己,表示此时走到了第step+1个盒子面前*/
            //判断是否符合规则,如果符合就输出符合的,如果不符合的继续运行for循环,if判断语句无法进入,所以返回上一级dfs,即直接运行biaozhi[i]=0;
			biaozhi[i]=0;
			/*book[i]=0
			*/
		}
	}
	return;//这里表示这一级别的dfs函数已经结束了,返回上一级 dfs函数 

}
int main()
    {
	dfs(1);   //dfs函数的开始 
	printf("可能性一共有%d种",total);
	return 0;
    }

其实这个深度优先遍历法有着自己另外一个更加被接受的名字叫做回溯算法,其原理的主要中心思想其实总结为一句话来说就是当完成第一次基本输入后不断回溯到上一步,然后发散到其他没有选择的状态。简单来说

java 深度优先遍历 递归 深度优先遍历栈实现_java 深度优先遍历 递归_02

 就是123  我们回溯到1,重新选择未选择的3,之后得1,3,2

相应得我们可以回溯到开始将2作为起始点,之后继续输出。

二:迷宫问题

#include <stdio.h>
int p,q,min=100000;
int m,n; 
int a[100][100]; //1表示空地,2表示障碍物 
int sign[100][100]; //0表示未使用,1表示已使用 
void dfs(int x,int y,int step)
{
	if(x==p&&y==q)
	{
	 if(step<min)
	 {
	  min=step;
     }
	  return;
	}
	 //顺时针试探
	 //右
	if(a[x+1][y]==1&&sign[x+1][y]==0)
	 {  
	    sign[x+1][y]=1;
	 	dfs(x+1,y,step+1);
		sign[x+1][y]=0;
	 }
	 //下 
	if(a[x][y+1]==1&&sign[x][y+1]==0)
	 {  
	    sign[x][y+1]=1;
	 	dfs(x,y+1,step+1);
		sign[x][y+1]=0;
	 }
	 //左
	if(a[x-1][y]==1&&sign[x-1][y]==0)
	 {  
	    sign[x-1][y]=1;
	 	dfs(x-1,y,step+1);
		sign[x-1][y]=0;
	 }
	 	 //下 
	if(a[x][y-1]==1&&sign[x][y-1]==0)
	 {  
	    sign[x][y-1]=1;
	 	dfs(x,y-1,step+1);
		sign[x][y-1]=0;
	 }
	return; 
}
int main()
{
	int startx,starty;
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	    scanf("%d%d%d%d",&startx,&starty,&p,&q);
	    sign[startx][starty]=1;//已经访问 
		dfs(startx,starty,0); 
		printf("%d",min);

}

java 深度优先遍历 递归 深度优先遍历栈实现_面试_03

补优化算法:

#include <stdio.h>
int p,q,min=100000;
int m,n; 
int a[100][100]; //1表示空地,2表示障碍物 
int sign[100][100]; //0表示未使用,1表示已使用 
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1}; 
void dfs(int x,int y,int step)
{
	if(x==p&&y==q)
	{
	 if(step<min)
	 {
	  min=step;
     }
	  return;
	}
	 //顺时针试探
	 for(int k=0;k<=3;k++)
	{
		int tx,ty;
		tx=x+dx[k];
		ty=y+dy[k]; 
		if(a[tx][ty]==1&&sign[tx][ty]==0)
		{
		sign[tx][ty]=1;
		dfs(tx,ty,step+1);
		sign[tx][ty]=0;	
		}	
	}
	return;
}
int main()
{
	int startx,starty;
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	    scanf("%d%d%d%d",&startx,&starty,&p,&q);
	    sign[startx][starty]=1;//已经访问 
		dfs(startx,starty,0); 
		printf("%d",min);

}