深度优先搜索(DFS)

简介: 深度优先搜索(DFS)

深度优先搜索(DFS)

深度优先搜索,是从起点v0开始,优先往下v1,v2级搜索下去,同样的举例子:

假设有一个这样的文件夹:

image.png

里面有着大大小小的文件以及子文件夹,当你需要搜索一个名字为:仙士可.txt的文件时

你需要怎么遍历呢?

首先,我们把/text下的文件及文件夹称作为v0级文件,以此同理,vo级文件夹下的子文件为v1级...v2

广度优先搜索

在广度优先搜索中,我们是这样遍历的:

先遍历v0的所有文件,存储v1的所有需要遍历的文件夹,再遍历v1的所有文件,同时存储v2的文件夹....

深度优先搜索

深度优先搜索的做法为:

1:保存v0级别的所有文件,1,2,3,4,5,测试文本01.txt,测试文本02.txt,

2:先遍历v0级别的目录1,判断为目录,而不是目标文件

3:保存目录1的v1级子文件 11,12,测试文本11.txt

4:继续保存目录11的子文件 111,测试文本111.txt,

5:继续遍历目录11的第一个子文件夹111,由于111文件夹没有内容,则返回

6:继续遍历目录11的第二个文本测试文本111.txt,由于不匹配 仙士可.txt,则返回

7:目录11遍历完毕,返回

8:继续遍历12文件夹

...

深度优先搜索的做法是,从一个起点开始,一直遍历下去,直到满足条件或者没有数据遍历,则开始第二个点开始遍历,直到最后一个vo级数据遍历完毕

广度优先搜索和深度优先搜索

现在我们已经知道了广度优先搜索以及深度优先搜索的搜索步骤,

那么,它们之间的优缺点有哪些呢?什么时候要用广度优先什么时候要用深度优先呢?

我们根据它们之间的特性进行分析:

内存消耗

当子节点过多的时候,广度优先搜索需要保存更多的子节点数据以便于下次遍历,而深度优先搜索只需要保存当前节点的上下级节点

例如,

当v0级文件夹有10个文件夹,同时每个子文件夹也有10个文件夹(空文件夹)的时候.

广度优先在遍历到第20次的时候(vo级和v1级都遍历完),这时候的队列已经保存了10*10-20(已经遍历过)需要遍历的数据

而深度优先在这个时候,只保存了10(v0级文件夹)+0(v1级第一个已经遍历完毕)+10(v1级第二个遍历的栈)

深度优先由于只需要记录当前遍历的上下级节点,并且每次遍历完可以及时回收,所以内存消耗较少

广度优先由于需要记录上级所有节点以及当前的下级节点,在子节点数过多的时候,需要消耗更多的内存

最优解

之前的那个搜索文件的需求,我们稍微改一改:

一个文件夹里面有n级的子文件夹,有着5,6个名字为"仙士可.txt"的文件,现在我们需要找到层级最高(离v0最近的)的那个"仙士可.txt"文件

这个时候,该怎么找呢?

深度优先搜索的做法是这样的:

找到该文件之后,记录该文件的层级(假设为v5)以及路径

继续查找,找到之后,如果层级大于v5,则忽略,如果小于v5,则覆盖之前的层级以及路径

...

这样子,我们就可以找到层级最高的"仙士可.txt"

而在广度优先搜索中,我们只需要v0下去逐层查找,找到之后立即返回即可

深度优先搜索可以在消耗少量内存的情况下找到一个解,但这个解并不一定是最优解,如果需要找最优解,需要遍历全部数据,消耗更多的时间

广度优先搜索消耗更多的内存,消耗相对较少的时间,找出的是最优解,

算法实现

深度优先准备工作如下:

1:结果集数组,将匹配正确的结果集数组保存

2:递归函数,栈实现深度搜索

3:创建一个数组,用于记录已经遍历的文件夹(通用写法,当你的v2级文件夹,有一个是v0级的快捷方式的时候,需要判断一下是否已经遍历过了,如果有就不再遍历)

由于深度优先搜索的特性,需要通过一个全局的结果集数组保存结果值,在栈里面判断该次搜索任务是否完成

算法需求拆分:

1:递归函数,foreach当前级别的文件数组的时候,继续调用该函数,去foreach下一个级别的文件数组,直到找到结果集数组或者遍历全部完成

2:获取子级数据 在调用一个文件夹的时候,去获取他的子级并且开始下一次循环

3:根据结果集判断搜索任务是否完成

4:判断任务数据  判断当前数据是否已经遍历过,是否跳过

php实现如下:

<?php
$resultData = \[\];
$ergodic = \[\];//通过php的hash数组特性,直接$ergodic\[hash(文件夹名)\]=1; 进行表示该文件夹名已遍历
$rootPath = '/www/easyswoole/tioncico_demo/test';
search($rootPath,$ergodic,$resultData);
/**
 * search
 * @param     $path  //需要搜索的目录
 * @param     $ergodic //已遍历数据存储
 * @param     $resultData //结果数据存储
 * @param int $level
 * @author Tioncico
 * Time: 11:51
 */
function search($path,&$ergodic,&$resultData,$level=1){
    //判断目录是否已经遍历过
    if (checkTask($ergodic, $path)) {
        return null;
    }
    //标记该目录已经遍历过
    $ergodic\[md5($path)\] = 1;
    //获取目录的数据
    $fileData = getDirData($path);
    //判断是文件,还是文件夹
    foreach ($fileData as $file) {
        //判断是否完成搜索,在这里,只要$resultData不为空就当成成功搜索
        if (!empty($resultData)){
            break;
        }
        //过滤本级目录以及上级
        if ($file == '.' || $file == '..') {
            continue;
        }
        $filePath = "{$path}/$file";
        echo "当前遍历文件:{$filePath}\\n";
        if (is_file($filePath)) {//如果是文件,则处理文件
            //判断文件终止情况
            if (checkFile($filePath)) {
                $resultData\[\] = $filePath;
                echo "文件搜索成功,路径为:{$filePath}\\n";
                return $filePath;
            }
        } elseif (is_dir($filePath)) {//如果是目录,则继续遍历
            search($filePath,$ergodic,$resultData,$level+1);
        } else {
            continue;
        }
    }
    return null;
}
/**
 * 扫描文件夹(获取子级数据)
 * getDirData
 * @param $path
 * @return array
 * @author Tioncico
 * Time: 11:55
 */
function getDirData($path)
{
//扫描文件夹
    $file = scandir($path);
    return $file;
}
//判断遍历条件是否完成
function checkFile($data)
{
    if (basename($data) == '仙士可.txt') {
        return true;
    }
    return false;
}
//判断该任务是否已经遍历过
function checkTask($ergodic, $path)
{
    return isset($ergodic\[md5($path)\]);
}
//子级数据入队列
function pushQueue(&$queue, $data)
{
    array_push($queue, $data);
}

输出:

image.png\

去除终止条件时候的输出:

image.png

以广度优先搜索对比:

image.png

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2hrq8tku2rqco

目录
相关文章
|
6月前
|
算法
深度优先搜索(DFS)的基础理解与实现
深度优先搜索(DFS)的基础理解与实现
80 0
|
存储 前端开发 算法
深度优先搜索(DFS)和广度优先搜索(BFS)
深度优先搜索(DFS)和广度优先搜索(BFS)
121 0
|
算法
DFS and BFS
DFS and BFS
49 0
DFS(深度优先搜索)和BFS(宽度优先搜索)
DFS(深度优先搜索)和BFS(宽度优先搜索)
79 0
|
算法
DFS深度优先搜索
DFS深度优先搜索
|
算法
浅谈递归回溯DFS和BFS
前言 我们在解题的过程中经常遇到各种题型的分类,其中有几类是经常交替出现或者同时出现的 递归 回溯 DFS BFS
|
算法
【和zqy学算法】Day1:DFS与BFS
【和zqy学算法】Day1:DFS与BFS
150 0
|
算法 Java Python
【算法题解】 Day6 BFS | DFS
今天的算法是 「BFS | DFS」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
103 0
|
算法 Java 索引
【算法题解】 Day10 BFS | DFS
今天的算法是 「BFS | DFS」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
102 0
|
存储 机器学习/深度学习 人工智能
一文搞懂深度优先搜索、广度优先搜索(dfs、bfs)
你问一个人听过哪些算法,那么深度优先搜索(dfs)和宽度优先搜索(bfs)那肯定在其中,很多小老弟学会dfs和bfs就觉得好像懂算法了,无所不能,确实如此,学会dfs和bfs暴力搜索枚举确实利用计算机超强计算大部分都能求的一份解,学会dfs和bfs去暴力杯混分是一个非常不错的选择!
224 0
一文搞懂深度优先搜索、广度优先搜索(dfs、bfs)