技术向智力题&算法题

DFS && BFS算法学习总结

2016-09-12  本文已影响3798人  会发光的二极管

两种算法比较

一般说来,能用DFS解决的问题都能用BFS解决。DFS通过递归实现,易于实现,DFS的常数时间开销会比较少,所以大多数情况下优先考虑DFS实现。然后就是,DFS容易栈溢出,而BFS可以自己控制队列的长度。最后,BFS加上评估函数可以变成A算法,DFS加上评估函数可以变成IDA算法。

DFS算法

核心思想

它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底,这种尽量往深处走的概念即是深度优先的概念。
代码表示如下:

/**
 * DFS核心伪代码
 * 前置条件是visit数组全部设置成false
 * @param n 当前开始搜索的节点
 * @param d 当前到达的深度
 * @return 是否有解
 */
bool DFS(Node n, int d){
    if (isEnd(n, d)){//一旦搜索深度到达一个结束状态,就返回true
        return true;
    }

    for (Node nextNode in n){//遍历n相邻的节点nextNode
        if (!visit[nextNode]){//
            visit[nextNode] = true;//在下一步搜索中,nextNode不能再次出现
            if (DFS(nextNode, d+1)){//如果搜索出有解
                //做些其他事情,例如记录结果深度等
                return true;
            }

            //重新设置成false,因为它有可能出现在下一次搜索的别的路径中
            visit[nextNode] = false;
        }
    }
    return false;//本次搜索无解

eg.二叉树中和为某一值的路径
题目描述
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

class Solution {
public:
     vector<vector<int>> res;
     vector<int> path;
    void find(TreeNode* root,  int sum)
    {
        if (root == NULL)return;
        path.push_back(root->val);
        if (!root->left && !root->right && sum == root->val)
            res.push_back(path);
        else
        {
            if (root->left)
                find(root->left, sum - root->val);
            if (root->right)
                find(root->right, sum - root->val);
        }
        path.pop_back();
    }
    vector<vector<int>> FindPath(TreeNode* root,int expectNumber) {
        find(root, expectNumber);
        return res;
    }
};

BFS算法

核心思想

广度优先搜索一个图的时候是按照树的层次来搜索的,(层次遍历),队列来实现,形象的说,这里有点像辐射形状的搜索方式,从一个节点,向其旁边节点传递病毒,就这样一层一层的传递辐射下去,知道目标节点被辐射中了,此时就已经找到了从起点到终点的路径。
核心代码如下:

/**
 * 广度优先搜索
 * @param Vs 起点
 * @param Vd 终点
 */
bool BFS(Node& Vs, Node& Vd){
    queue<Node> Q;
    Node Vn, Vw;
    int i;

    //初始状态将起点放进队列Q
    Q.push(Vs);
    hash(Vw) = true;//设置节点已经访问过了!

    while (!Q.empty()){//队列不为空,继续搜索!
        //取出队列的头Vn
        Vn = Q.front();

        //从队列中移除
        Q.pop();

        while(Vw = Vn通过某规则能够到达的节点){
            if (Vw == Vd){//找到终点了!
                //把路径记录,这里没给出解法
                return true;//返回
            }

            if (isValid(Vw) && !visit[Vw]){
                //Vw是一个合法的节点并且为白色节点
                Q.push(Vw);//加入队列Q
                hash(Vw) = true;//设置节点颜色
            }
        }
    }
    return false;//无解
}   

对于一个题目来说,要标志节点是否访问过,用数组是一种很快速的方法,但有时数据量太大,很难用一个大数组来记录时,采用hash是最好的做法。实际上visit数组在这里也是充当hash的作用。(PS:至于hash是什么?得自己去了解,它的作用是在O(1)的时间复杂度内取出某个值)

参考资料

深度优先算法(DFS)
广度优先算法(BFS)
图的基本算法
程序员必须知道的十大算法
图的遍历之DFS&BFS

上一篇下一篇

猜你喜欢

热点阅读