3007基于二叉链表的二叉树叶子结点到根结点的路径的求解(附DFS在树里的应用分析,思路详解)

以下代码用到的前置知识:DFS算法
可以看这个视频~只用看这个就能懂了~
DFS深搜解决迷宫问题(原理分析+代码实现)_哔哩哔哩_bilibiliicon-default.png?t=LA92https://www.bilibili.com/video/BV1bK4y1C7W2?from=search&seid=1822028840745610874&spm_id_from=333.337.0.0
描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法求出每个叶子结点到根结点的路径。

输入

多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘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
#include
#include
#include
#include
using namespace std;
typedef struct BNode
{
	char data;
	struct BNode* lchild, * rchild;
}*BTree, BNode;
vector 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;
}

你可能感兴趣的:(这只是一场训练,数据结构,c++,dfs,二叉树)