【数据结构与算法】输出二叉树中从每个叶子结点到根结点的路径 C++实现(二叉树+栈+深度优先搜索)

二叉树叶子节点到根节点的路径

题目描述

给定一棵二叉树的后序遍历序列 post[s1..t1] 和中序遍历序列 in[s2..t2],设计一个算法,输出二叉树中从每个叶子节点到根节点的路径。请使用栈的数据结构解决。

输入格式

输入包括两行:

  • 第一行为后序遍历序列 post[s1..t1]
  • 第二行为中序遍历序列 in[s2..t2]

保证构成一棵唯一的二叉树。

输出格式

输出多行,每行表示一条从叶子节点到根节点的路径,路径上的节点按照从叶子节点到根节点的顺序排列。

样例 #1

样例输入 #1

DEBGFCA
DBEAFGC

样例输出 #1

ABD
ABE
ACFG

提示

首先,后序遍历的最后一个元素是树的根。然后,你可以在中序遍历序列中找到这个根,这样就可以确定哪些元素在左子树,哪些在右子树。然后,你可以递归地构造左子树和右子树。

利用栈的特性,可以方便地实现从叶子节点到根节点的路径的输出。在遍历过程中,将路径上的节点压入栈中,当遍历到叶子节点时,就可以将栈中的元素按照出栈顺序输出,即得到从叶子节点到根节点的路径。


思路

先检查传入的二叉树 T 是否存在。如果存在,就将当前节点的数据 T->data 压入栈 stk。这是因为栈的特性决定了它能够保存从叶子节点到根节点的路径。

接着,检查当前节点是否是叶子节点,即它的左右子树 T->leftT->right 是否都不存在。如果是叶子节点,就输出从栈底到栈顶的所有元素,即从根节点到当前叶子节点的路径,然后从栈中弹出当前节点。

如果当前节点不是叶子节点,就递归地对左子树 T->left 和右子树 T->right 调用 findPath。这样,就可以遍历到所有的叶子节点。

最后,无论当前节点是否是叶子节点,都会在遍历完其所有子树后从栈中弹出当前节点。这是因为在返回到父节点之前,需要清理当前节点的信息,否则会影响其他路径的输出。

算法分析

对于时间复杂度,算法需要遍历二叉树的所有节点,所以时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是二叉树的节点数。空间复杂度主要取决于栈的大小和递归深度,最坏情况下,当二叉树退化为链表时,空间复杂度为 O ( n ) O(n) O(n)


AC代码

#include <algorithm>
#include <cstring>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using Status = int;
using ElemType = char;

const int N = 1e4 + 7;
const int TRUE = 1;
const int FALSE = 0;
const int OK = 1;
const int ERROR = 0;
const int INFEASIBLE = -1;
// const int OVERFLOW = -2;

int n;
ElemType a[N];

struct TreeNode {
	ElemType data;
	struct TreeNode *left, *right;
};
using BiTree = TreeNode *;

struct Stack {
	ElemType data[N];
	int top;
};

BiTree createBiTree(char *last, char *mid, int len) {
	if (len <= 0) {
		return NULL;
	}
	// 后序序列最后一个节点为根节点
	char root = last[len - 1];
	// 中序序列中找根节点
	int index = 0;
	while (mid[index] != root) {
		index++;
	}

	// 创建根节点
	BiTree T = (TreeNode *)malloc(sizeof(TreeNode));

	T->data = root;
	T->left = createBiTree(last, mid, index);
	T->right = createBiTree(last + index, mid + index + 1, len - index - 1);
	return T;
}

Status initStack(Stack &stk) {
	stk.top = 0;
	return OK;
}

Status push(Stack &stk, ElemType e) {
	if (stk.top >= N) {
		return ERROR;
	}
	stk.data[++stk.top] = e;
	return OK;
}

Status pop(Stack &stk) {
	if (!stk.top) {
		return ERROR;
	}
	stk.top--;
	return OK;
}

ElemType getTop(Stack stk) { return stk.data[stk.top]; }

void findPath(BiTree T, Stack &stk) {
	if (T) {
		push(stk, T->data);
		if (!T->left && !T->right) {
			for (int i = 1; i <= stk.top; i++) {
				cout << stk.data[i];
			}
			cout << endl;
			pop(stk);
			return;
		}
		findPath(T->left, stk);
		findPath(T->right, stk);
		pop(stk);
	}
}

int main() {
	char post[N], in[N];
	cin >> post >> in;

	BiTree T = createBiTree(post, in, strlen(post));
	Stack stk;
	initStack(stk);

	findPath(T, stk);
	return 0;
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我可以提供一个C语言算法实现。具体实现思路如下: 1. 给定二叉树节点,设计一个递归函数,每次遍历到一个节点,就将该节点的值添加进列表,并将它的左右子树作为参数传递给递归函数。 2. 当遍历到叶子节点时,将列表的所有节点值按顺序输出即可。 3. 二叉树的性质,可以从任意节点开始递归,因此只需要设计一个函数就能输出任意节点到节点路径上的所有节点值。 具体的C语言实现代码如下: ``` #include<stdio.h> #include<stdlib.h> // 定义二叉树的节点结构 typedef struct Node { int data; struct Node* left; struct Node* right; }Node; // 初始化二叉树,返回节点指针 Node* initTree() { Node* root = (Node*)malloc(sizeof(Node)); root->data = 1; Node* left_child = (Node*)malloc(sizeof(Node)); left_child->data = 2; left_child->left = NULL; left_child->right = NULL; Node* right_child = (Node*)malloc(sizeof(Node)); right_child->data = 3; right_child->left = NULL; right_child->right = NULL; root->left = left_child; root->right = right_child; return root; } // 递归输出节点到节点路径上的所有节点值 void printPath(Node* root) { if (root == NULL) { return; } // 将当前节点的值添加到列表 printf("%d ", root->data); // 如果当前节点是叶子节点,输出整个列表的节点值 if (root->left == NULL && root->right == NULL) { printf("\n"); return; } // 遍历左子树 printPath(root->left); // 遍历右子树 printPath(root->right); } int main() { Node* root = initTree(); printPath(root->left); return 0; } ``` 这段代码输出的是节点的左子树每个节点到节点路径上的所有节点值。如果需要输出其他节点到节点路径上的值,只需要修改`printPath(root->left)`的参数即可。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值