深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次
一、具体步骤
1、从一个支点开始,选择一条分支
2、沿着分支一直走到无路可走
3、重新回到分支,选择另一条路,重复第二步
4、直到所有点全部遍历完成。
二、举例分析
例:从3出发,有多少路可以选择
- 3->1->2->5
- 3->1->2->6
- 3->1->4
- 3->7
- 3->8->9->11
- 3->8->10->12
1、将图解析为数组模式,相连的用 1 表示,不相连用 0 表示,每个有12元素,放入数组$arr中。
[1,2,3,4,5,6,7,8,9,10,11,12];
$arr=[
[0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], //1 与 2、3、4相连
[1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], //2 与 1、5、6相连
[1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], //3 与 1、7、8相连
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //4 与 1相连
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //5 与 2相连
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //6 与 2相连
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], //7 与 3相连
[0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], //8 与 3、9、10相连
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0], //9 与 8、11相连
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], //10 与 8、12相连
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], //11 与 9相连
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], //12 与 10相连
];
2、从3开始分别找出与之相连的元素,$arr[2],记录已经走过的元素 $existArr[]=[3]
[1,0,0,0,0,0,1,1,0,0, 0, 0]
//$arr 是初始化数组
//$enter 是起点
//$existArr 是已经走过的元素集合 【3】
//$roadList 是已经走过的路线 3
function findRoad($arr, $enter, $existArr, $roadList)
foreach ($arr[2] as $key => $val) {
//找出相连的元素
if ($val == 1) {
//判断元素是否已经走过
if (!in_array($key, $existArr)) {
//找到相邻的未走过的元素,存入路线
$this->walkRoad($arr, $key, $existArr, $roadList);
}
}
}
}
3、相连的元素是1、7、8,并将以找到的元素记录下来 $existArr[]=[3,1,7,8],并从1开始重复第二、第三步。
//$arr 是初始化数组
//$key 是找到相邻的元素 1
//$existArr 是已经走过的元素集合 【3】
//$roadList 是已经走过的路线 3
function walkRoad($arr, $key, $existArr, $roadList){
//把找到的元素放入已经走过的集合中,防止以后重复走
$existArr[] = $key;
//把找到的元素写入路线中
$roadList .= '->' . ($key + 1);
//将路线保存下来
$this->removeRoad($arr[$key],$existArr,$roadList);
//从找到的元素开始,从新找与之相邻的元素
$this->findRoad($arr, $key + 1, $existArr, $roadList);
}
4、保存路线的时候,应注意是否是完整的路线。例:【3->1->2】因为下边还有5、6,顾不用保存。
//$original 是走到当前元素$key的状态$arr[$key] 例:走到1,$arr【0】,[0,1,1,1,0,0,0,0,0,0, 0, 0]
//$existArr 是已经走路的元素集合 【3、1】
//roadList 是走过的路线 3->1
function removeRoad($original,$existArr,$roadList){
//将以走的元素作为key值,value补1 【3=>1,1=>1】
$testArr=array_combine($existArr,array_fill(0,count($existArr),1));
//用1可以走的路线状态和已经走的路线状态比较
$diffArr=array_diff_assoc($original,$testArr);
//如果为true,则说明没有路可以走了,将路线保存下来
if(is_bool(array_search(1,$diffArr))){
$this->roadArr[]=$roadList;
}
}
三、完整代码
<?php
/**
* Created by PhpStorm.
* User: Wallace
* Date: 2020/5/20
* Time: 18:00
*/
/*
* 根据数组去找寻路线
*/
class dfs
{
private $enter = [];
public $roadArr = [];
//初始化路径
public function getRoad($arr, $enter)
{
$this->enter = $enter;
$existArr = [$this->enter - 1];
$roadList = $this->enter;
$this->findRoad($arr, $enter, $existArr, $roadList);
return $this->roadArr;
}
//根据参数,开始寻找路径
protected function findRoad($arr, $enter, $existArr, $roadList)
{
foreach ($arr[$enter - 1] as $key => $val) {
if ($val == 1) {
if (!in_array($key, $existArr)) {
$this->walkRoad($arr, $key, $existArr, $roadList);
}
}
}
}
//限制已经存在的路,写入路线
protected function walkRoad($arr, $key, $existArr, $roadList)
{
$existArr[] = $key;
$roadList .= '->' . ($key + 1);
$this->removeRoad($arr[$key],$existArr,$roadList);
$this->findRoad($arr, $key + 1, $existArr, $roadList);
}
//检测是否无路可走
protected function removeRoad($original,$existArr,$roadList){
$testArr=array_combine($existArr,array_fill(0,count($existArr),1));
$diffArr=array_diff_assoc($original,$testArr);
if(is_bool(array_search(1,$diffArr))){
$this->roadArr[]=$roadList;
}
}
}
$arr=[
[0,1,1,1,0,0,0,0,0,0, 0, 0], //1
[1,0,0,0,1,1,0,0,0,0, 0, 0], //2
[1,0,0,0,0,0,1,1,0,0, 0, 0], //3
[1,0,0,0,0,0,0,0,0,0, 0, 0], //4
[0,1,0,0,0,0,0,0,0,0, 0, 0], //5
[0,1,0,0,0,0,0,0,0,0, 0, 0], //6
[0,0,1,0,0,0,0,0,0,0, 0, 0], //7
[0,0,1,0,0,0,0,0,1,1, 0, 0], //8
[0,0,0,0,0,0,0,1,0,0, 1, 0], //9
[0,0,0,0,0,0,0,1,0,0, 0, 1], //10
[0,0,0,0,0,0,0,0,1,0, 0, 0], //11
[0,0,0,0,0,0,0,0,0,1, 0, 0], //12
];
$dfs=new dfs();
$roadArr=$dfs->getRoad($arr,3);
var_dump($roadArr);
//结果
array(6) {
[0]=>
string(10) "3->1->2->5"
[1]=>
string(10) "3->1->2->6"
[2]=>
string(7) "3->1->4"
[3]=>
string(4) "3->7"
[4]=>
string(11) "3->8->9->11"
[5]=>
string(12) "3->8->10->12"
}