查找二叉树中从根结点到指定结点的路径(C)
有一棵二叉树,如下图所示:

其中 # 表示空结点。
先序遍历:A B D E G C F
问题:怎么得到从根结点到任意结点的路径呢?
示例:输入 G,怎么得到从结点 A 到结点 G 的路径呢?
很明显,我们一眼就能看出来路径是 A B E G。如何通过程序得到这条路径就是我们需要做的。
定义二叉树的 链式存储结构 如下:
typedef struct BiTNode {
char data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;// 二叉树结点的存储结构
二叉树的遍历有三种方式:即先序遍历,中序遍历,后序遍历。
这里采用先序遍历,因为我们需要的是到达指定结点即可。没必要其他多余的操作。而先序就是先访问结点再递归子树。满足要求。
由于需要 路径 而不是输出先序遍历的结果,因此需要一个 栈 来保存路径。由于数据是 字符型 的,但是不知道路径长度,因此采用 链栈。
链栈 结构如下:
typedef struct StackNode {
char data;
struct StackNode* next;
}StackNode, * Stack;// 链栈
完整代码:
/*************************************************************************
实现功能: 输出从根结点到指定结点的路径
编译环境: Visual Studio 2019
更新日期: 2019年10月8日23:01:29
作者: wowpH
*************************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>// exit,malloc头文件
#define EMPTY_NODE '#'
typedef struct BiTNode {
char data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;// 二叉树的链式存储结构
typedef struct StackNode {
char data;
struct StackNode* next;
}StackNode, * Stack;// 链栈
// 创建二叉树结点
BiTree createBiTNode();
// 创建二叉树
void createBiTree(BiTree* T);
// 创建栈结点
Stack createStackNode();
// 查找结点并返回路径头结点
void findNode(Stack S, BiTree T, char nodeToFind);
// 输出路径
void outputPath(Stack S);
// 输出提示
void outputTips();
int main() {
outputTips();
printf("输入二叉树:");
BiTree root = NULL;
createBiTree(&root);
char enter = getchar();
printf("输入指定结点:");
char nodeToFind = getchar();
Stack stack = createStackNode();
findNode(stack, root, nodeToFind);
// 输出路径信息
if (stack->next == NULL) {
printf("未找到结点'%c'\n", nodeToFind);
} else {
printf("路径:");
outputPath(stack);
printf("\n");
}
return 0;
}
// 创建二叉树结点
BiTree createBiTNode() {
BiTree bt = (BiTree)malloc(sizeof(BiTNode));
if (bt == NULL) {
printf("错误:创建二叉树结点错误!\n");
exit(0);
}
bt->lchild = NULL;
bt->rchild = NULL;
return bt;
}
// 创建二叉树
void createBiTree(BiTree* T) {
char ch = getchar();
if (ch == '\n' || ch == EMPTY_NODE) {
return;
}
*T = createBiTNode();
(*T)->data = ch;
createBiTree(&(*T)->lchild);// 左子树
createBiTree(&(*T)->rchild);// 右子树
}
// 创建栈结点
Stack createStackNode() {
Stack ret = (Stack)malloc(sizeof(StackNode));
if (ret == NULL) {
printf("错误:创建栈结点错误!\n");
exit(0);
}
ret->next = NULL;
return ret;
}
// 查找结点
void findNode(Stack S, BiTree T, char nodeToFind) {
if (S->next != NULL && S->next->data == nodeToFind) {
return;// 已找到
}
if (T == NULL) {// 空树
return;
}
// 入栈
Stack sNew = createStackNode();
sNew->data = T->data;
sNew->next = S->next;
S->next = sNew;
// 查找子树
findNode(S, T->lchild, nodeToFind);
findNode(S, T->rchild, nodeToFind);
// 若不是要查找的结点,出栈
if (S->next->data != nodeToFind) {
Stack delete = S->next;
S->next = delete->next;
free(delete);
}
}
// 输出路径,递归
void outputPath(Stack S) {
if (S->next != NULL) {
outputPath(S->next);
printf(" ");
}
printf("%c", S->data);
}
// 输出提示
void outputTips() {
printf("1、先序输入二叉树\n");
printf("2、空结点用'%c'表示\n", EMPTY_NODE);
printf("3、Enter表示输入结束\n");
printf("4、不能输入多余的字符\n");
printf("5、查找的字符不能是换行符和'%c'\n\n", EMPTY_NODE);
}
/*************************************************************************
1、先序输入二叉树
2、空结点用'#'表示
3、Enter表示输入结束
4、不能输入多余的字符
5、查找的字符不能是换行符和'#'
示例1:
输入二叉树:ABD##EG###CF###
输入指定结点:G
路径:A B E G
示例2:
输入二叉树:124##56##7##3##
输入指定结点:7
路径:1 2 5 7
*************************************************************************/
智能推荐
1051: 输出利用先序遍历创建的二叉树中的指定结点的孩子结点java实现
可能是jdk版本问题,SWUST上面的没有skipNbytes();这个方法。错了一百遍。。。。。,虽然有这个题用这个跳过\r\n也是错的,因为第二行还有其他的空白符且在要被搜索的字符之前 用bufferedinputStream的话它是一次性将所有输入读入缓冲区,虽然还不知道缓冲区是个啥, ** No enclosing instance of type Main is accessible. ...
SWUST OJ 1052:输出利用先序遍历创建的二叉树中的指定结点的双亲结点
题干: 思路:不需要双指针,只要判断当前结点的左右孩子有无关键元素,有的话就输出当前结点的数据,否则输出# 代码:...
SWUST OJ 1053: 输出利用先序遍历创建的二叉树中的指定结点的度
1053: 输出利用先序遍历创建的二叉树中的指定结点的度 题目链接-1053: 输出利用先序遍历创建的二叉树中的指定结点的度 解题思路 先序递归建树,然后递归搜索指定结点 然后判断该节点的左右孩子个数,即判断左右子树是否为空 具体操作见代码 附上代码...
猜你喜欢
人工智能基础-数学方法-形式逻辑
1956 年召开的达特茅斯会议宣告了人工智能的诞生。在人工智能的襁褓期,各位奠基者们,包括约翰·麦卡锡、赫伯特·西蒙、马文·明斯基等未来的图灵奖得主,他们的愿景是让“具备抽象思考能力的程序解释合成的物质如何能够拥有人类的心智”。 通俗地说,理想的人工智能应该具备抽象意义上的学习、推理与归纳能力,其通用性将远远强于解决国际象棋或是围棋...
P3397 地毯——题解2020.10.3
P3397 地毯 思路分析 定义一个二维数组 a[ ][ ]存放每个点覆盖地毯的个数,下标表示每个点的坐标; 设置一个二重循环依次遍历每个地毯覆盖的坐标范围,使地毯覆盖范围内点的值+1; 打印出该二维数组 a[ ][ ]即为本题答案; 注意事项 由题可知:对于20%的数据,有 n≤50,m≤100;对于100%的数据,有 n,m≤1000;所以数组定义为a[1003][1003]...
反射注解案例
1、反射案例: 需求 写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法 实现: 配置文件 反射 步骤: 创建对象 将需要创建的对象的全类名和需要执行的方法定义在配置文件中 在程序中加载读取配置文件 使用反射技术来加载类文件进内存 执行方法 第一步:Person类(创建对象) 第二步:配置文件 pro.properties(将需要创...
lambert与half lambert模型逐顶点和逐片元的漫反射光照
兰伯特模型 逐顶点光照 逐片元光照: 效果对比:左边为逐片元光照。右边为逐顶点光照。右边明暗交界处有较明显的锯齿 半兰伯特光照模型 兰伯特模型的一个问题就是背光面只有一种颜色,缺乏立体感。Half Lambert用于解决这个问题 半兰伯特模型公式: 与兰伯特模型的差别主要在于不同于将背光面光都设为0,它将背光的光也即负值也映射到[0,1]区间。避免了背光的颜色只有0这一种值。需要注意的是,half...
