0
点赞
收藏
分享

微信扫一扫

深度优先 / 广度优先 / 回溯: data structure & algorithm

楚木巽 2021-09-30 阅读 98
深度/广度 优先搜索 广泛用于 `图 和 树` 搜索

1 深度优先搜索 ( DFS, Depth First Seach )

1. 思想: 尽可能 深 地 搜索

(1) 从 given node 出发, 朝 某个 方向 往前 walk, 边 walk 边 visit, 走到头后, 回退 一步

(2) if found adjacent 且 not visited node, 以 此 node 为 new given node, 重复(1); 若 not found, 再 回退一步

要用 FILO 的 stack / 递归 实现

2. for tree equivalent to preorder traverse

`root ( visit -> walk) -> lchild -> rchild`

实现及调试 见 ( BFS 也见 )

https://www.jianshu.com/p/bf7d6665b564

note:
二叉搜索树 前序遍历 时, 不用 record 每个 node 是否已 visited,
因为 通过 

push node 
while ( ! stk.empty() )
  -> top
  -> visit 
  -> pop 
  -> push node->rchild 
  -> push node->lchild

已实现 root -> left -> right
<=> 
root_layer1(`push -> top -> visit -> pop`) 
-> rchild_layer2(`push`) 
-> lchild_layer2(push -> top -> visit -> pop) 
-> ...
-> rchild_layern(`push`) 
-> lchild_layern(`push -> top -> visit -> pop`) 
-> 回退 -> `top rchild_layern -> visit -> pop`
-> rchild_layern+1(push rchild_layern->rchild)
-> rchild_layern+1(push rchild_layern->lchild -> top ->visit -> pop)
-> ...
// iteration version:
// 用 栈, 时/空 复杂度 O(N)
std::vector<int>
preorder_tree_walk_iter(B_tree_node* proot)
{
    //(1) vector: 存 output sequence
    std::vector<int> result_vec;

    //(2) stack: 存 即将 遍历的 pnode, 
    //           后 进 先 出/遍历
    std::stack<const B_tree_node*> stk;

    //(3) root pointer 先入栈
    if (proot != nullptr)
        stk.push(proot);

    //(4) stack 再循环: 若 栈 not empty
    while (!stk.empty())
    {
        // 1) get/top old_top elem/pnode
        // 2) pop top elem
        // 3) old_top.key 入 vector
        // 4) old_top->rchild 入栈
        // 5) old_top->lchild 入栈
        const B_tree_node* p = stk.top();
        stk.pop();

        result_vec.push_back(p->key);

        if (p->rchild != nullptr)
            stk.push(p->rchild);
        if (p->lchild != nullptr)
            stk.push(p->lchild);
    }

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}
3. 可用于 检测环路:record 每个遍历过的 node 的 parent,
若一 node 被再次遍历 且 parent 不同, 则有环

状态记录:
`标记 已搜索过的 node, 以 防止 重复搜索`

2 广度优先搜索 (BFS, Breadth First Search)

1. 思想: 尽可能 广地 搜索

(1) 从 given node 出发 -> `visit`

(2) if found its `adjacent 且 not visited` node1..noden 
    -> `visit node1... noden (Breadth)`

(3) for node1-n
        loop (2)

要用 FIFO 的 queue 实现

2. for tree equivalent to layer-order traverse

layer1
layer2_1 ... layer2_n
layer3_1 ... layer3_n
push root
while( ! que.empty() )
    top
    visit
    pop
    push lchild
    push rchild
// 用 queue, 时/空 复杂度 O(N)
std::vector<int>
BFS_tree_walk(B_tree_node* proot)
{
    //(1) vector: 存 output sequence
    std::vector<int> result_vec;

    //(2) queue: 存 即将 遍历的 pnode, 
    //           后 进 先 出/遍历
    std::queue<const B_tree_node*> que;

    //(3) root pointer 先入栈
    if (proot != nullptr)
        que.push(proot);

    //(4) stack 再循环: 若 栈 not empty
    while (!que.empty())
    {
        // 1) get/top old_top elem/pnode
        // 2) pop top elem
        // 3) old_top.key 入 vector
        // 4) old_top->lchild 入 queue
        // 5) old_top->rchild 入 queue
        const B_tree_node* p = que.front();
        que.pop();

        result_vec.push_back(p->key);

        if (p->lchild != nullptr)
            que.push(p->lchild);
        if (p->rchild != nullptr)
            que.push(p->rchild);
    }

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}

3. Dijkstra Prim

举报

相关推荐

0 条评论