2020-01-01 关于深度优先搜索算法正确性的论证

深度优先搜索示意图如下:
root
l0 , r0
l1 l2 l3 ; r1 r2
其中root两个儿子节点l0,r0, l0三个儿子节点l1,l2,l3; r0有2个儿子节点r1,r2

上图树结构搜索顺序为 root->l0->l1->l2->l3->r0->r1->r2
其规律是 ,
a, 先遍历根节点;
b,遍历完当前节点后,先遍历完其所有后代节点 ,再遍历其右兄弟节点;
c, 遍历后代节点时先遍历左儿子节点;
这三条规律后文中统称深度优先搜索规律R;

深度优先搜索代码大致如下:

T* root = getRoot();
stack s;
s.push(root);
while(!s.empty())
{
    T* t= s.top();
    s.pop();
    proc(t); //遍历操作;
    vector& vec = t->children();
    for(int i = vec.size()-1; i>=0; --i)
    {
          s.push(vec[i]);
    }
}

其中 T* root 是具有树形结构的对象,其子节点位于 children()中,按从左到右顺序排列;
下面来论证以上代码确实可以实现深度优先搜索;

利用归纳法证明,归纳假设如下:
A,假设上述代码执行完proc(t)时已经按照深度优先搜索规律刚刚遍历完此时变量t对应的节点x,
B,此时栈s中存放的节点依次是 :(1)x所有的右兄弟节点,(2)x的父节点的所有 右兄弟节点
(3)x的父节点的父节点的所有右兄弟节点 ....... 直到没有父节点

代码后续从右到左将x的子节点push到栈s中,设x的子节点数为 n,
分2种情形讨论:
1, n = 0 ,则for循环没做任何事,

到下个while循环 ,根据假设B, 取出x的第一个右兄弟节点(如果有)遍历,此时符合R-b,进而符合A;

如果无右兄弟节点,根据假设B,将取出x的父节点的第一个右兄弟节点(如果有)遍历,
此时 ,x的父节点最右子节点已经遍历完,根据假设A,x的父节点所有子节点已经按照A遍历完;
则此时遍历x的父节点的第一个右兄弟节点符合R-b 进而符合A;

如果x的父节点的第一个右兄弟节点也不存在,将取其父父节点右兄弟节点,
此时说明x的父节点及其所有子节点已遍历完,进而父父节点所有子节点已遍历完,符合R-b,进而符合A;

....
以此类似分析,始终符合 A;

并且n=0时没有入栈操作,而且只是从栈顶出栈,假设B得以保持;

2, n!=0 , 则 for循环把x所有子节点从左到右依次排在栈前;
到下个while循环,会先处理x的第一个左儿子节点,符合R-c ,进而符合A

同时,栈中元素此时依次为: x的左儿子的所有右节点 -> x的所有右节点,...
符合B

综上,无论哪种情形,在循环过程中,A,B始终得以保持;
最后只需证明对初始态,A,B成立;proc(root)后,栈为空显然成立;

综上,就证明了以上代码确实可以实现深度优先搜索。

你可能感兴趣的:(2020-01-01 关于深度优先搜索算法正确性的论证)