回溯算法 DFS 和 BFS

!!!本文思路、代码均参考于[代码大多参考于此文章]!!!

!!!本文思路、代码均参考于[代码大多参考于此文章]!!!:https://labuladong.online/algo/essential-technique/backtrack-framework-2/#%E4%B8%80%E3%80%81%E5%85%A8%E6%8E%92%E5%88%97%E9%97%AE%E9%A2%98

引入

  • 看了一些DFS和BFS的文章 , 我对这两个搜索算法的理解又深了一些
  • 我之前一直搞不明白一个问题 : 什么时候用DFS? 什么时候用BFS?

先对二叉树的dfs和bfs来分析一波:

  • 二叉树的dfs(深度优先遍历) 顾名思义就是竖着遍历 , 直到遍历到叶子节点(第一次遍历到的叶子节点一定是左下的那个) , 然后开始往回走
    所以dfs 最大的特点就是–>要遍历完所有可能的路径—>再去寻找答案

  • bfs(广度优先遍历)呢? 那也就是横着遍历了呗—>bfs一般用队列实现,将同一层的节点都装进队列中

     因而,bfs在寻找最短路径时,比dfs好用点(当然,只是某些情况下好用.毕竟bfs要占用的空间太多了 . 二叉树每层又是呈指数型增加,那不kuku网上增,得用多少空间啊)
     为什么是某些情况好用的-->你想啊,一个差不多的二叉树,找他的最短路径
     bfs咋找?-->一层层找 , 比如第一个叶子节点在第三层--->那bfs找到第三层之后就不用再找了
     dfs呢?--->找出所有的路径 , 再比较一下谁最短.
    

综上啊

  • dfs啥时候用呢?---->要找所有可能情况的时候

  • bfs呢—>最短路径

      当然,这里最短路径可能包括 : 
      - 走迷宫,有的格子是围墙不能走,从起点到终点的最短距离是多少? 如果这个迷宫带[传送门]可以瞬间传送呢?
      - 比如果两个单词,要求你通过某些替换,把其中一个变成另一个,每次只能替换一个字符,最少要替换几次?
      - 再比如 连连看游戏,两个方块消除的条件不仅仅是图案相同,还得保证两个方块之间的最短连线不能多与两个拐点 . 玩连连看时,点击两个坐标,如何判断它俩的最短线之间有几个拐点的?
    
      [当然,以上都是一幅图,让你从一个起点,走到终点,问最短路径.]
    

以下附上某AI的回答:

	通常情况下,可以根据以下几点考虑何时使用深度优先搜索(DFS)和广度优先搜索(BFS)算法:
- 使用DFS:
  1. 当问题需要遍历所有可能的路径或状态时,可以使用DFS。
  2. 当问题的解可能在深层次的状态中,且不需要最短路径时,DFS是一个不错的选择。
  3. 当问题涉及到图的遍历、连通性检测、拓扑排序等情况时,DFS通常是一个简单且有效的选择。

- 使用BFS:
  1. 当问题需要在最短路径上找到解时,可以使用BFS。
  2. 当问题需要按层级遍历或搜索时,BFS是一个很好的选择。
  3. 当问题需要找到最短路径、最短距离或最短步数时,BFS通常是更好的选择。

总的来说,DFS适用于深度优先搜索、递归问题和状态空间搜索,而BFS适用于广度优先搜索、最短路径问题和层级遍历。根据问题的特点和需求,选择合适的搜索算法可以提高算法效率和解决问题的准确性。

回溯算法和dfs的区别

回溯算法和dfs算法极为相似,本质上就是一种暴力穷举算法。
区别就是:回溯算法是在遍历【树枝】,dfs算法是在遍历【节点】
(其实没啥区别)

回溯算法(DFS)

站在回溯树的节点上,你只需要思考3个问题 :

  1. 路径 : 也就是已经做出的选择
  2. 选择列表 : 也就是你当前可以做的选择
  3. 结束条件 : 也就是到达决策树底层,无法再做选择的条件

1.基本框架

result = []
def backtrack(路径,选择列表):
	if 满足结束条件:
		result.add(路径)
		return

	for 选择 in 选择列表:
		做选择
		backtrack(路径,选择列表)
		撤销选择

2.例题:【1,2,3】的全排列

  • 如图,1,2,3的全排列我们可以用一个树来表示(回溯算法是记录路径!!)

在这里插入图片描述

  • 大致思想是这样的(先拿出来一支杈 分析分析)
    在这里插入图片描述

再重复一遍

  • 站在一个回溯树的节点上,只需要思考3个问题:
    1.路径:也就是已经做出的选择(往后看看)
    2.选择列表:也就是当前可以做的选择(往前看看)
    3.结束条件:到达决策树底层,无法再做选择的条件(看看自己啥时候over)
  • 只针对上面有色儿的那一支杈

      - 对于上面的“粉色”节点:
      	路径:没有
      	选择列表:【1】
      	结束条件:遍历到叶子节点
      - 对于上面的“黄色”节点:
      	路径:【1】
      	选择列表:【2,3】
      	结束条件:遍历到叶子节点
      - “红色”:
      	路径:【1,2,3】
      	选择列表:没有
      	结束条件:到达结束条件
    

3.代码详解

  • 基本思想完事了,我们来仔细分析下代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.完整代码

import java.util.LinkedList;
import java.util.List;

//import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;

public class Main{
	static LinkedList<List<Integer>> list = new LinkedList<>();

	public static void main(String[] args) {
		int[] nums = {1,2,3};
		System.out.println(permute(nums));
	}
	
	//输入一组不重复的数字,返回他们的全排列
	static List<List<Integer>> permute(int[] nums){
		//记录[路径]
		LinkedList<Integer> track = new LinkedList<>();
		// [路径] 中的元素会被标记为true,避免重复使用
		boolean[] used = new boolean[nums.length];
		
		backtrack(nums,track,used);
		return list;
	}

	// 路径:记录在track中
	//选择列表:nums中不存在于track的那些元素(used[i] 为false)
	//结束条件:nums中的元素全都在track中出现
	static void backtrack(int[] nums, LinkedList<Integer> track, boolean[] used) {
		//结束条件
		if(track.size() == nums.length) {
			list.add(new LinkedList(track));
			return;	//返回上一级backtrack
		}
		
		for(int i=0;i<nums.length;i++) {
			//排除不合法的选择
			if(used[i]) {
				//nums[i]已经在track中,跳过
				continue;
			}
			
			//做选择
			track.add(nums[i]);
			used[i] = true;
			//进入下一层决策树
			backtrack(nums, track, used);
			//取消选择
			track.removeLast();
			used[i] = false;
		}
		
		//return;	//返回上一级的backtrack(不加也行,循环结束,自动返回上一级backtrack)
		
	}
}

经典dfs(回溯)解法----排列/组合/子集问题

解这些题的时候还是可以把他们看做一棵树

1.计算所有子集

还是遍历一棵树 , 树棍上标着要遍历的下一个nums中的元素 , 每个节点就是组合出来的子集 . 而我们可以轻易发现 , 每层组合出来的子集,由相同元素个数组成 且元素个数等于层数

0层 0个元素组成
1层 1个元素组成
2层 2个元素组成
3层 3个元素组成

由此 , 我们把这棵树的节点都遍历出来 , 不就是[1,2,3]的所有子集了吗
在这里插入图片描述

框架

class Soluction{
	List<List<Integer>> res = new LinkedList<>();//存放所有子集
	LinkedList<Integer> track = new LinkedList<>();	//记录回溯算法的递归路径

	//主函数
	public List<List<Integer>> subsets(int[] nums){
		backtrack(nums,0);
		return res;
	}
	
	//回溯算法核心函数,遍历子集问题的回溯树
	void backtrack(int[] nums,int start){	//start是用来去重的(只要每次索引从start开始,那么,start前的元素就不会再被使用了)

		//前序位置,每个节点的值都是一个子集
		res.add(new LinkedList<>(track));
	
		//回溯算法标准框架
		for(int i = start; i < nums.length; i++){
			//做选择
			track.addLast(nums[i]);
			//通过 start 参数控制树枝的遍历,避免产生重复的子集
			backtrack(nums,i+1);
			//撤销选择
			track.removeLast();
		}
	}
}

完整代码

import java.util.LinkedList;
import java.util.List;

public class Main{
	static List<List<Integer>> res = new LinkedList();	//用来存放结果集
	static int[] nums = {1,2,3};
	static List<Integer> track = new LinkedList<Integer>();	//用来记录路径(并进行添加和回溯)
	public static void main(String[] args) {
		dfs(nums, 0);
		System.out.println(res);	//output:[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
	}
	
	//回溯算法
	public static void dfs(int[] nums,int start) {
		res.add(new LinkedList<Integer>(track));
		
		//回溯经典框架
		for(int i=start;i<nums.length;i++) {
			//选择
			track.add(nums[i]);
			//递归
			dfs(nums, i+1);
			//撤销选择
			track.remove(track.size()-1);
		}
	}
}

2.组合

子集完事了 , 那现在想想 , 如果让你输出nums = [1,2,3] 中拿2个元素形成的所有组合 , 怎么做?

  • 那不就是输出树的第2层吗

例题 : 给定两个整数n和k,返回方位[1,n]中所有可能的k个数的组合.

  • 那不就是输出这一层吗 .
    在这里插入图片描述
  • 框架
class Soluction{
	static List<List<Integer>> res = new LinkedList();
	static List<Integer> track = new LinkedList();

	//主函数
	public List<List<Integer>> combine(int n, int k){
		backtrack(1,n,k);
		return res;
	}

	//回溯函数
	void backtrack(int start,int n,int k){
		if(k == track.size()){
			res.add(new LinkedList<>(track));
			return;
		}
		
		for(int i=start;i<=n;i++){
			//选择
			track.addLast(i);
			//递归
			backtrack(i+1,n,k);
			//撤销选择
			track.removeLast();
		}
	}
}
  • 完整代码
import java.util.LinkedList;
import java.util.List;

public class Main{
	static List<List<Integer>> res = new LinkedList();	//用来存放结果集
//	static int[] nums = {1,2,3};
	static List<Integer> track = new LinkedList<Integer>();	//用来记录路径(并进行添加和回溯)
	public static void main(String[] args) {
		dfs(1,3,2);	//1到3,输出两个元素的所有组合
		System.out.println(res);
	}
	
	//回溯算法
	public static void dfs(int start,int n,int k) {
		if(track.size() == k) {
			res.add(new LinkedList<Integer>(track));
			return;
		}
		
		for(int i=start; i<=n;i++) {
			//选择
			track.add(i);
			//递归
			dfs(i+1, n, k);
			//撤销选择
			track.remove(track.size()-1);	//remove(索引)
		}
	}
}

岛屿问题

二维矩阵遍历框架

  • 可以正常遍历
void dfs(int[][] grid,int i,int j,boolean[][] visited) {
		int m = grid.length;
		int n = grid[0].length;
		if(i<0 || j<0 || i>=m || j>=n) {
			//超出索引边界
			return;
		}
		if(visited[i][j]) {
			//该点已经遍历过
			return;
		}
		//进入节点(i,j)
		visited[i][j] = true;
		dfs(grid, i-1, j, visited);//上
		dfs(grid, i+1, j, visited);//下
		dfs(grid, i, j-1, visited);//左
		dfs(grid, i, j+1, visited);//右
	}
  • 也可以使用方向数组遍历
static int[][] dirs = new int[][] {{-1,0},{1,0},{0,-1},{0,1}};//上,下,左,右(方向数组)
	public static void dfs(int[][] grid,int i,int j,boolean[][] visited) {
		int m = grid.length;
		int n = grid[0].length;
		if(i<0 || j<0 || i>=m || j>=n) {
			//超出索引边界
			return;
		}
		if(visited[i][j]) {
			//该点已经遍历过
			return;
		}
		//进入节点(i,j)
		visited[i][j] = true;
		
		//递归遍历上下左右的节点
		for(int[] d : dirs) {
			int next_i = i + d[0];
			int next_j = j + d[1];
			dfs(grid, next_i, next_j, visited);
		}
		
	}

例题:岛屿数量

力扣 岛屿数量

  • 代码实现
class Solution{
	//主函数,计算岛屿的数量
	int numIslands(char[][] grid) {
		int res = 0;
		int m = grid.length;	//行数
		int n = grid[0].length;		//列数
		//遍历grid
		for(int i=0;i<m;i++) {
			for(int j=0;j<n;j++) {
				if(grid[i][j] == '1') {
					//每发现一个岛屿 , 岛屿数加一
					res++;
					//然后使用dfs把与他相邻的岛屿都淹了
					dfs(grid,i,j);
				}
			}
		}
		return res;
	}
	
	//从(i,j)开始,将与之相邻的陆地都变成海水
	void dfs(char[][] grid,int i,int j) {
		int m = grid.length;
		int n = grid[0].length;
		
		//超出边界
		if(i < 0 || j < 0 || i >= m || j >= n) {
			return;
		}
		//该点已经是海水了
		if(grid[i][j] == '0') {
			return;
		}
		
		//将(i,j)变成海水
		grid[i][j] = '0';
		//淹没该点旁边的陆地
		dfs(grid, i-1, j);
		dfs(grid, i+1, j);
		dfs(grid, i, j-1);
		dfs(grid, i, j+1);
	}
}

例题:岛屿的最大面积

力扣:岛屿的最大面积

class Solution {
    int maxAreaOfIsland(int[][] grid) {
    	int m = grid.length;
    	int n = grid[0].length;
    	
    	int res = 0;
    	
    	//遍历岛屿
    	for(int i=0;i<m;i++) {
    		for(int j=0;j<n;j++) {
    			if(grid[i][j] == 1) {
    				res = Math.max(res,dfs(grid,i,j));
    			}
    		}
    	}
    }
    
    //淹没(i,j)相邻的陆地 , 并返回淹没的陆地面积
    int dfs(int[][] grid,int i,int j) {
    	int res = 0;
    	int m = grid.length;
    	int n = grid[0].length;
    	if(i<0 || j<0 || i>=m || j>=n) return 0;
    	if(grid[i][j] == 0) return 0;
    	
    	//将(i,j)变为海水
    	grid[i][j] = 0;
    	//计算周围岛屿数量
    	return dfs(grid, i+1, j)
    			+dfs(grid, i-1, j)
    			+dfs(grid, i, j+1)
    			+dfs(grid, i, j-1)+1;
    }
}

BFS

  • BFS算法 都是用 队在这里插入代码片列 这种数据结构,每一次将一个节点周围的所有节点加入队列
  • BFS 和 DFS 最主要的区别是 : BFS找到的路径一定是最短的(但代价就是空间复杂度可能比DFS大很多)

代码框架

//伪码

//计算从起点start 到终点target的最短距离
int bfs(Node start,Node target){
	Queue<Node> q;	//核心数据结构
	Set<Node> visited;	//避免走回头路

	q.offer(start);	//将起点加入队列
	visited.add(start);
	
	while(q not empty){
		int sz = q.size();
		//将 当前队列中的所有节点啊向四周扩散
		for(int i = 0;i < sz; i++){
			Node cur = q.poll;	//取队头元素
			//判断是否达到终点
			if(cur is target)
				return step;
				
			//将 cur 的相邻节点加入队列
			for(Node x : cur.adj()){	//cur.adj()表示与cur相邻的节点
				if(x not in visited){
					q.offer(x);
					visited.add(x);
				}
			}
		}
	}
	//如果走到了这里,说明在图中没有找到目标节点
}

练习----二叉树的最小深度

力扣111. 二叉树的最小深度

  1. 二叉树的最小深度 给定一个二叉树,找出其最小深度。
    最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
    说明:叶子节点是指没有子节点的节点。
    示例 1:
    在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示: 树中节点数的范围在 [0, 105] 内
-1000 <= Node.val <= 1000

思路:
首先明确起点start 和 终点target是什么?怎么判断到达了终点(也就是结束条件)?
—>显然 , 起点就是 root 根节点 , 终点就是最靠近根节点的那个叶子节点 叶子节点就是两个子节点都是null的节点

if(cur.left == null && cur.rigth == null)
	//到达了叶子节点
  • 核心代码
//给定一颗树的根节点,求这棵树的最小深度
int minDepth(TreeNode root){
	if(root == null) return 0;
	Queue<TreeNode> q = new LinkedList<>():
	q.offer(root);
	//root本身就是一层,depth初始化为1
	int depth = 1;

	while(!q.isEmpty){
		int sz = q.size();
		//将 当前队列中的所有节点向四周扩散
		for(int i = 0; i < sz; i++){
			TreeNode cur = q.poll();
			//判断是否到达终点
			if(cur.left == null && cur.right == null)
				 return depth;
			//将cur的相邻节点加到队列中
			if(cur.left != null)
				q.offer(cur.left);
			if(cur.rigth != null)
				q.offer(cur.right);
		}
			//这里增加步数
			depth++;
	}
	return depth;
}

在这里插入图片描述

  • 完整代码
import java.util.LinkedList;
import java.util.Queue;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建一棵二叉树用于测试
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);

        Main solution = new Main();
        int minDepth = solution.minDepth(root);
        System.out.println("Minimum depth of the binary tree: " + minDepth);
    }

    //bfs
    //给定二叉树的头结点,输出这颗树的最小深度
    public int minDepth(TreeNode root) {
    	if(root == null) return 0;
    	//bfs必用队列		可能会有一个集合visited来存储走过的路(避免走回头路)--->此题不用
    	Queue<TreeNode> q = new LinkedList<>();
    	
    	q.offer(root);	//先把根节点放进去
    	int depth = 1;	//要算上根节点那一层
    	
    	
    	while(! q.isEmpty()) {
    		int sz = q.size();	//sz只是 二叉树 一层的节点个数--->所以,for完一层后,还会再while,再让sz = 下一层的节点个数
    		
    		//将 当前队列中的所有节点向四周扩散
    		for(int i = 0;i < sz; i++) {
    			TreeNode cur = q.poll();	//每次都取队头元素
    			
    			//找到叶子节点
    			if(cur.left == null && cur.right == null) 
        			return depth;
        		
    			//不是叶子节点,那就cur的子节点存入队列中
    			if(cur.left != null) q.offer(cur.left);
    			if(cur.right != null) q.offer(cur.right);
    		}
    		depth++;	
    	}
    	return depth;	//这里返回depth,其实是做了一个保险操作(因为在正常情况下,一个二叉树,不会没有叶子节点) 
    }
}

练习例子

蓝桥杯迷宫问题

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
  //bfs方法-->队列
  //按照DLRU的方向找路径
  static char[][] c = new char[30][50]; //输入题目迷宫
  static int[][] visited = new int[30][50]; //判断每个坐标是否走过
  static int[][] step = {{1,0},{0,-1},{0,1},{-1,0}}; //方向数组(DLRU)
  static char[] direction = {'D','L','R','U'};
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        for(int i=0;i<30;i++)
        	c[i] = scan.nextLine().toCharArray();
        System.out.println(bfs());
        scan.close();
    }
    
    
    //存储路径字母序的类
    static class Node{
      int x;
      int y;
      String str;
      public Node(int x,int y,String str){
        this.x = x;
        this.y = y;
        this.str = str;
      }
    }

    public static String bfs(){
      Queue<Node> q = new LinkedList();
      q.offer(new Node(0, 0, ""));
      visited[0][0] = 1;
      String shunxv = ""; //存储到达每个节点的路径(字母序)

      while(! q.isEmpty()){
        int sz = q.size();

        for(int i=0;i<sz;i++){
          Node t = q.poll();
          int x1 = t.x;
          int y1 = t.y;
          String str1 = t.str;
          //结束条件
          if(x1 == 29 && y1 == 49){
            shunxv = str1;
            break;
          }
          //队列中节点的子节点入队-->此题应按照字母序
          for(int j=0;j<4;j++){
            int x2 = x1 + step[j][0];
            int y2 = y1 + step[j][1];
            if(x2>=0 && x2<=29 && y2>=0 && y2<=49 && c[x2][y2] == '0'&& visited[x2][y2] == 0){
              q.offer(new Node(x2,y2,str1+direction[j]));
              visited[x2][y2] = 1;
            }
          }
        }
      }
      return shunxv;
    }

}

DFS(拓展,也不算拓展,只拓了,没展)

我在读这篇<回溯算法>的文章时 , 本以为他会讲回溯算法和dfs的区别 但是,文章后面说----其实回溯算法就是dfs…(无语啊啊啊啊)

import java.util.Scanner;

public class Main {

    static int n;
    static int[] a;
    static boolean book[];

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        n=scanner.nextInt();
        a=new int[n+2];
        book=new boolean[n+2];
        dfs(1);
        scanner.close();
    }
    public static void dfs(int k) {
        // 回头条件
        if(k==n+1){ //说明n个盒子都已经放完了
            for(int i=1;i<=n;i++){
                System.out.print(a[i]+" ");
            }
            System.out.println();
            return; //这里的return是返回上一级dfs(可以理解为,方案一执行完了,还要进行方案二的排序)
        }

        // 放牌等操作
        for(int i=1;i<=n;i++){   //进行1~n号牌的排序
            if(book[i]==false){ //当这个盒子里没有牌时,可以进行以下操作
                a[k]=i;         //i号牌放入k号盒子中
                book[i]=true;   //标记盒子不为空
                dfs(k+1);       //带着手中的牌,走向下一个盒子
                book[i]=false;  //箱子置空。其实每次循环都执行到dfs(k++),只有当执行到没有路可走的时候,才会"回头";也就相当于例子中的,要从3号箱开始往回一个个收牌了
            }
        }
        return;

    }
}
  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: DFS(深度优先搜索)和BFS(广度优先搜索)算法是图论中常见的两种算法,用于遍历图或树的节点。以下是C++实现: DFS算法实现: ```c++ #include <iostream> #include <vector> #include <stack> using namespace std; void dfs(vector<vector<int>>& graph, vector<bool>& visited, int start) { stack<int> s; s.push(start); while (!s.empty()) { int node = s.top(); s.pop(); if (!visited[node]) { visited[node] = true; cout << node << " "; for (int i = graph[node].size() - 1; i >= 0; --i) { int next_node = graph[node][i]; if (!visited[next_node]) { s.push(next_node); } } } } } int main() { int n = 5; vector<vector<int>> graph(n); graph[0].push_back(1); graph[0].push_back(2); graph[1].push_back(3); graph[1].push_back(4); vector<bool> visited(n, false); dfs(graph, visited, 0); return 0; } ``` BFS算法实现: ```c++ #include <iostream> #include <vector> #include <queue> using namespace std; void bfs(vector<vector<int>>& graph, vector<bool>& visited, int start) { queue<int> q; q.push(start); while (!q.empty()) { int node = q.front(); q.pop(); if (!visited[node]) { visited[node] = true; cout << node << " "; for (int i = 0; i < graph[node].size(); ++i) { int next_node = graph[node][i]; if (!visited[next_node]) { q.push(next_node); } } } } } int main() { int n = 5; vector<vector<int>> graph(n); graph[0].push_back(1); graph[0].push_back(2); graph[1].push_back(3); graph[1].push_back(4); vector<bool> visited(n, false); bfs(graph, visited, 0); return 0; } ``` 这里我们以一个简单的无向图为例,节点从0到4编号,图的邻接表表示为: ``` 0: 1, 2 1: 0, 3, 4 2: 0 3: 1 4: 1 ``` DFS算法BFS算法的输出结果都是:0 2 1 4 3。 ### 回答2: DFS(深度优先搜索)和BFS(广度优先搜索)是两种常用的图遍历算法,都可以用来实现C语言。 DFS算法通过递归或者栈的方式实现,可以从图的某个顶点开始,沿着一条路径一直到达没有未探索的邻居节点为止,然后返回到前一个顶点继续探索其他未探索的邻居节点。可以用以下C语言代码实现DFS算法: ```c #include <stdio.h> #define SIZE 100 int visited[SIZE]; //用来标记节点是否访问过 int graph[SIZE][SIZE]; //图的邻接矩阵表示 void dfs(int node) { printf("%d ", node); visited[node] = 1; for(int i = 0; i < SIZE; i++) { if(graph[node][i] && !visited[i]) { dfs(i); } } } int main() { //初始化visited和graph //调用dfs函数 dfs(0); //从节点0开始深度优先搜索 return 0; } ``` BFS算法通过队列的方式实现,可以从图的某个顶点开始,将其加入队列,然后依次将队列中的节点访问并将其邻居节点加入队列,直到队列为空。可以用以下C语言代码实现BFS算法: ```c #include <stdio.h> #define SIZE 100 int visited[SIZE]; //用来标记节点是否访问过 int graph[SIZE][SIZE]; //图的邻接矩阵表示 void bfs(int node) { int queue[SIZE]; int front = 0, rear = 0; queue[rear++] = node; visited[node] = 1; while(front < rear) { int curNode = queue[front++]; printf("%d ", curNode); for(int i = 0; i < SIZE; i++) { if(graph[curNode][i] && !visited[i]) { queue[rear++] = i; visited[i] = 1; } } } } int main() { //初始化visited和graph //调用bfs函数 bfs(0); //从节点0开始广度优先搜索 return 0; } ``` 以上就是用C语言实现DFSBFS算法的代码。在实际应用中,可以根据具体场景选择使用DFS还是BFS来进行图的遍历。 ### 回答3: DFS(深度优先搜索)和BFS(广度优先搜索)算法都是用于图的遍历的常见算法。它们在图遍历的顺序、搜索方式和空间复杂度上有所差异。 DFS是一种先深入后回溯的搜索方法。它从起点开始,沿着图的一条路径一直遍历到尽头,然后回溯到上一个节点,继续探索其他未遍历的路径,直到整个图都被遍历完。DFS常用递归或栈的方式实现。 BFS是一种逐层扩展的搜索方法。它从起点开始,首先遍历起点的所有邻接节点,然后依次遍历邻接节点的邻接节点,以此类推,直到整个图都被遍历完。BFS常用队列的方式实现,每次将待遍历节点加入队列,并在从队列中取出节点时,将其邻接节点加入队列。 在C语言中,实现DFSBFS算法可以借助图的表示方式和遍历的数据结构。一种常见的图的表示方式是邻接矩阵或邻接表,用于存储图的顶点和边的关系。而在遍历过程中,可以借助一个访问标记数组,用于标记节点是否被访问过。 对于DFS算法的实现,可以通过递归函数实现,递归函数的参数包括当前遍历的节点、访问标记数组等。递归函数的主体部分可以按照DFS的逻辑进行实现。 而对于BFS算法的实现,可以通过队列来实现,首先将起点加入队列,然后循环取出队列中的节点,并将其邻接节点依次加入队列,直到队列为空。在每次取出节点时,可以将其标记为已经访问过。 总之,DFSBFS算法在C语言中的实现需要借助图的表示方式,以及递归函数或队列等数据结构。具体实现的细节还可以根据具体问题的需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值