03-树3 Tree Traversals Again(25 分)

本文介绍了一种通过栈实现的非递归二叉树中序遍历方法,并给出了一道算法题目,要求根据给定的栈操作序列生成对应的二叉树并输出后序遍历序列。文章提供了完整的C语言代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

03-树3 Tree Traversals Again (25 分)

An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.

Figure 1

Figure 1

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N(≤30)N (≤30)N(30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to NNN). Then 2N2N2N lines follow, each describes a stack operation in the format: “Push X” where X is the index of the node being pushed onto the stack; or “Pop” meaning to pop one node from the stack.

Output Specification:

For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop

Sample Output:

3 4 2 6 5 1

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXN 30
#define OK 1
#define ERROR 0

int pre[MAXN], in[MAXN], post[MAXN];

//定义栈结构
struct SNode {
	int data;
	struct SNode *next;
};
typedef struct SNode *Stack;

//创建一个栈
Stack CreateStack() {
	Stack S;
	S = (Stack)malloc(sizeof(struct SNode));
	if(S) S->next = NULL;
	return S;
}

//判断栈是否为空
int IsStackEmpty(Stack S) {
	return S->next == NULL;
}

//入栈
void Push(Stack S, int data) {
	Stack p;
	p = CreateStack();
	p->data = data;
	p->next = S->next;
	S->next = p;
}

//出栈
int Pop(Stack S, int *result) {
	Stack p = S->next;
	if (IsStackEmpty(S)) return ERROR;
	*result = p->data;
	S->next = p->next;
	free(p);
	return OK;
}

//获取字符串中的数字
int GetInputNum(char input[]) {
	int result = 0, i, temp;
	for (i = 3; i < strlen(input); i++) {
		if (input[i] >= '0' && input[i] <= '9') {
			temp = (int)(input[i] - '0');
			result = result * 10 + temp;
		}
	}
	return result;
}

//解题函数
//构造post序列
//preL为pre数组起始下标
//inL为in数组起始下标
//postL为post数组起始下标
//n为总节点个数
void Solve(int preL, int inL, int postL, int n) {
	//root为根结点数据,L为左子树节点个数,R为右子树节点个数
	int root, i, L, R;
	if (n == 0) return;
	if (n == 1) {
		post[postL] = pre[preL];
		return;
	}
	//根结点数据为pre数组第一个元素的数据
	root = pre[preL];
	//post数组最后一个元素应为根节点的数据
	post[postL + n - 1] = root;
	//在in数组找到与根节点数据相同的元素下标
	for (i = 0; i < n; i++)
		if (in[inL + i] == root)
			break;
	L = i;
	R = n - L - 1;
	//对左子树求解
	//左子树pre数组起始位置应为根节点后一个位置(preL+1)
	//左子树in数组起始位置为根结点左侧,因此起始位置不变(inL)
	//左子树数据应在post数组最前面,因此起始位置不变(postL)
	//左子树总节点数为L
	Solve(preL + 1, inL, postL, L);
	//对右子树求解
	//右子树pre数组起始位置应为左子树最后一个元素的下一个位置(preL+L+1)
	//右子树in数组起始位置为根结点右侧,而根结点左侧有L个左子树的元素,因此确定位置(inL+L+1)
	//右子树数据应在post数组L个左子树部分的后一个位置(postL+L)
	//右子树总节点数为R
	Solve(preL + L + 1, inL + L + 1, postL + L, R);
}

//根据post数组输出结果
void PrintResult(int n) {
	int i;
	for (i = 0; i < n; i++) {
		if (i == 0) printf("%d", post[i]);
		else printf(" %d", post[i]);
	}
	printf("\n");
}

int main(void) {
	char input[100] = "\0", temp[100] = "\0";
	int N, i, preCount = 0, inCount = 0, popResult, num;
	Stack S = CreateStack();

	i = scanf("%d\n", &N);
	for (i = 0; i < 2 * N; i++) {
		gets_s(input);
		strncpy(temp, input, 3);
		temp[3 - 1] = 0;
		//入栈
		if (!strcmp(temp, "Pus")) {
			num = GetInputNum(input);
			Push(S, num);
			pre[preCount] = num;
			preCount++;
		}
		//出栈
		if (!strcmp(temp, "Pop")) {
			Pop(S, &popResult);
			in[inCount] = popResult;
			inCount++;
		}
	}
	Solve(0, 0, 0, N);
	PrintResult(N);

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值