深度优先搜索(DFS)递归与非递归实现逻辑详解

本文探讨了递归与非递归算法的区别及其在数据结构中的应用,以二叉树先序遍历为例,详细解析了如何使用栈将递归算法转化为非递归形式,并以01背包问题为实例介绍了递归与非递归算法的设计思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  递归与非递归:

       数据结构对于学习编程的人来说是非常重要的,我们在现实生活碰到的各种烦难问题可以用递归来实现,一个递归思想就把问题给简单化了,但是我们都知道递归是非常耗时的,一旦数据量庞大起来,递归次数多了,这个时间是非常恐怖的。所以一般我们都会把一些递归问题给非递归化,来达到某一定的效率。通常递归转化为非递归用到了栈和队列,今天就详解用栈来实现转化的逻辑处理,并且以(01背包为主讲例子).

      DFS:深度优先搜索,相当于树的先序搜索。在这我们现以数据结构中经典的先序遍历的递归与非递归来打开主题.

 

 

                                

     其先序搜索为:1,2,4,5,3;

      递归实现:

void PreorderRecursive(Bitree root){
  if (root) {
    visit(root);
    PreorderRecursive(root->lchild); 
    PreorderRecursive(root->rchild); 
  }
}

 

    相信递归这个每个人都弄得懂,这里就不BB了.       

    非递归借助栈来完成转化(考研的小伙伴们要弄懂):

 

void PreorderNonRecursive(Bitree root){
  stack stk;
  stk.push(root);//节点入栈
  while(!stk.empty()){
    p = stk.top();//栈顶元素出栈并且访问该节点
    visit(p);
    stk.pop();
    if(p.rchild) stk.push(p.rchild);//右边节点入栈
    if(p.lchild) stk.push(p.lchild);
  }
}

     

 

           第一步:1号节点入栈。

          第二步:当栈不为空的时候弹出栈顶元素并且访问该节点,当栈为空的时候转第五步。

          第三步:弹出的栈顶元素的右和左节点入栈(如果存在的话).

   

         第四步:转到步骤二。

        第五步:结束。

 

    相信这个很容易理解。那么我们今天就直扑主题了。

    01背包问题。

    已知 有n个物品  他们的重量分别为 weight[i] = {i1,i2,....,in},价值分别为value[i] = {i1,i2,..in};

    背包的承重为m.求其最大能装下的价值 和.

    首先我们来考虑递归算法。递归逻辑非常简单.

   我们以这个简单例子分析:

    weight[] = {2,2,6};

   value [] = {6,3,5};

  n = 3;

  m = 6;//最大承重量

	static void  Backtrack(int i,int cp,int cw)
	{ //cw当前包内物品重量,cp当前包内物品价值
	    int j;
	    if(i>n)//回溯结束
	    {
	    	System.out.println("over");
	        if(cp>bestp)
	        {
	        	System.out.println("if  "+cw);
	            bestp=cp;
	            for(i=0;i<=n;i++) bestx[i]=x[i];
	        }
	    }
	    else {
	    	 for(j=0;j<=1;j++)  
	        {	        	
	            x[i]=j;
	            if(cw+x[i]*w[i]<=c)  
	            {
	                cw+=w[i]*x[i];
	                cp+=p[i]*x[i];
	                Backtrack(i+1,cp,cw);//递归调用
	                cw-=w[i]*x[i];//开始回溯
	                cp-=p[i]*x[i];
	                System.out.println("x["+i+"]   "+x[i]);
	            }//end if
	        }//end for
	    }//end else
	}//endstatic void  Backtrack(int i,int cp,int cw)
	{ //cw当前包内物品重量,cp当前包内物品价值
	    int j;
	    if(i>n)//回溯结束
	    {
	    	System.out.println("over");
	        if(cp>bestp)
	        {
	        	System.out.println("if  "+cw);
	            bestp=cp;
	            for(i=0;i<=n;i++) bestx[i]=x[i];
	        }
	    }
	    else {
	    	 for(j=0;j<=1;j++)  
	        {	        	
	            x[i]=j;
	            if(cw+x[i]*w[i]<=c)  
	            {
	                cw+=w[i]*x[i];
	                cp+=p[i]*x[i];
	                Backtrack(i+1,cp,cw);//递归调用
	                cw-=w[i]*x[i];//开始回溯
	                cp-=p[i]*x[i];
	                System.out.println("x["+i+"]   "+x[i]);
	            }//end if
	        }//end for
	    }//end else
	}//end

 

         构造我们的回溯树:

      

      黄色线条表示回溯, 先考虑一个背包情况,记录最大值,回溯根节点,判断2个背包,以此回溯。并记录下回溯记录情况,以及选中背包情况.

   懂得了上面的回溯树的构造之后,我们就可以将其改写成非递归。以下是伪代码

    

void Bag(Bitree root){
  stack stk;
  stk.push(root);//节点入栈
  while(!stk.empty()){
    p = stk.top();//栈顶元素出栈并且访问该节点
    visit(p);
    stk.pop();
    if(p.child)  stk.push(stk.child)//从右边开始入栈
  }
}     

      其实好多递归程序不能改写成非递归,重要的是你的树是怎样去构造他。

      最后支持原创,转载请注明转载出处

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值