以下代码用到的前置知识:DFS算法
可以看这个视频~只用看这个就能懂了~
描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法求出每个叶子结点到根结点的路径。
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出n行(n为叶子结点的个数),每行为一个叶子结点到根节点的路径(按照叶子结点从左到右的顺序)。
输入样例 1
abcd00e00f00ig00h00
abd00e00cf00g00
0
输出样例 1
dcba
ecba
fba
gia
hia
dba
eba
fca
gca
思考:
题目:······设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法求出每个叶子结点到根结点的路径。
每个叶子节点到根结点的路径,那必然会有情况是:同一个节点下衍生出的两个子节点,它们拥有几乎相同的前置路径,只是在最后的一步或几步产生了细微差异(回退到分支即可),并且考虑到树遍历算法的特殊性——无法指定路径,也不走“回头路”,而只能按照某一路径一气呵成地遍历所有节点,这就与DFS的思路不谋而合了,因为DFS也是:不走回头路,存在回退现象,遍历到不能遍历为止。
综上所述,当思路存在:不回头,有回退,遍历,路径存在重合只有某些地方有差异的时候,就是用到DFS的时候。
此刻正是,DFS之时!
下面是代码,其中,什么时候调用DFS,DFS的参数怎么写这两个问题以及解释都包含在注释里了~
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
typedef struct BNode
{
char data;
struct BNode* lchild, * rchild;
}*BTree, BNode;
vector<char> ans(100);
void Create(BTree& bt)
{
char c;
cin >> c;
if (c == '0')
bt = NULL;
else
{
bt = new BNode;
bt->data = c;
Create(bt->lchild);
Create(bt->rchild);
}
}
void Create(BTree& bt, char c)
{
if (c == '0')
bt = NULL;
else
{
bt = new BNode;
bt->data = c;
Create(bt->lchild);
Create(bt->rchild);
}
}
void DFSTraverse(BTree bt,int x)
{
if (bt)
{
ans[x] = bt->data;//如果当前节点存在,那么就从它这里走,它就算路径,在第几步走到了它(下标)存储它
if (!bt->lchild && !bt->rchild)//是叶子节点,那么可以输出遍历后的结果了
{
for (int i = x; i >= 1; i--)//由于是从叶子到根,所以要倒序遍历,x一开始传的是1,所以到1截止
cout << ans[i];
cout << endl;
}
/*
重点:
我什么时候要再次调用算法?
回答:想一想,DFS叫做“深度优先遍历”算法,用你的语文知识分析一下:“深度优先”是状语,是对算法的应用范围加以限制的,算法的主语是“遍历”,所以DFS是“用来遍历的算法”,那么要访问其他节点的时候就会自然而然地用到DFS了。反映到题目里就是:如果不是叶子节点,还需要继续「遍历」的时候,就会调用它。
调用算法的时候每个参数的含义都是什么?该如何处理算法中的参数才是正确的?
回答:首先需要把“地图”传进去吧,这个无需多言;第二个参数是我们需要仔细分析的。首先从这个题目上来看,同一结点的两个叶子节点在ans中会主动覆盖(因为路径长度一样,所以下标一样,所以在遍历右叶子节点的时候,会自动覆盖上一次存入的左叶子节点的信息),所以对叶子节点来说,不存在走到“else”的情况,不会用到DFS,忽略;再看普通节点:它们是有顺序的,每一次调用都说明又走了一步,因此它们之间不允许覆盖,所以要让ans[x]按顺序存储,就要在每次调用DFS的时候保证x每次都加1,以便让新节点存到新空间里,所以答案就浮出水面了——第二个参数写x+1.
*/
else
{
DFSTraverse(bt->lchild,x+1);
DFSTraverse(bt->rchild,x+1);
}
}
}
int main()
{
while (1)
{
char c;
cin >> c;
if (c == '0')
break;
BTree b;
Create(b, c);
/
int x = 0;//x就代表了当前已经走过结点的个数,又因为x是递增的,且每次调用都只加1,所以就相当于变相的记录了每一步都从谁那里取道
DFSTraverse(b, x+1);//所以其实一开始是把1传进去的
/
}
return 0;
}