查找二叉树中从根结点到指定结点的路径(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
*************************************************************************/
版权声明:本文为pfdvnah原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/pfdvnah/article/details/102387839

智能推荐

1051: 输出利用先序遍历创建的二叉树中的指定结点的孩子结点java实现

可能是jdk版本问题,SWUST上面的没有skipNbytes();这个方法。错了一百遍。。。。。,虽然有这个题用这个跳过\r\n也是错的,因为第二行还有其他的空白符且在要被搜索的字符之前 用bufferedinputStream的话它是一次性将所有输入读入缓冲区,虽然还不知道缓冲区是个啥, ** No enclosing instance of type Main is accessible. ...

SWUST OJ 1052:输出利用先序遍历创建的二叉树中的指定结点的双亲结点

题干: 思路:不需要双指针,只要判断当前结点的左右孩子有无关键元素,有的话就输出当前结点的数据,否则输出# 代码:...

SWUST OJ 1051:输出利用先序遍历创建的二叉树中的指定结点的孩子结点

题干: 思路:通过递归查找元素即可,本题比较简单 代码:...

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...

[React官网入门教程]三子棋游戏完整代码

入门教程: 认识 React 最终效果 完整代码 index.css部分 index.css部分...