03-树3 Tree Traversals Again (25分)(数据结构)(c语言实现)

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
在这里插入图片描述
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N 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

有些人可能对于英语题目很烦,我先把题目的大概意思讲一下,
文章是让你用栈的相关操作来操作元素,栈最后输出的元素和树有什么关系,就那上面的图片举个例子,我们可以发现,题目给的例子,栈最后输出的元素竟然是这棵树的中序遍历,同时我们也知道树的先序遍历,如果有认真听过课,我们可以知道有了树的先序和中序我们就那构成一棵树,或者知道了树的后序和中序遍历,我们也能构成一棵树,无论是哪两种,我们都需要中序遍历的存在。

关于如何用中序和先序或者是用后序和中序来构成一棵树:

链接: https://blog.csdn.net/shenbossed/article/details/106219675.
首先我们给出栈和树的节点的定义:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 30
typedef struct stack *PtrToSNode;
typedef PtrToSNode Stack;
typedef int ElementType;
struct stack
{
	int data;
	PtrToSNode next;
};
struct TreeNode
{
	int data;
	struct TreeNode *left;
	struct TreeNode *right;
};
typedef struct TreeNode *BinTree;

这是我们要实现的函数:

BinTree BuildTree(int *pre, int *in, int N);//根据中序和先序来建造一棵树
BinTree CreateTNode();//创造结点
Stack CreatS();//建栈
void push(Stack s,ElementType e);//入栈
ElementType pop(Stack s);//出栈
void PostOrderTravel(BinTree BT,int root);//后序遍历

我们先来看一下主函数:

int main()
{
	BinTree BT;
	Stack s;
	char c[5];
	int e,i;
	int N;
	int pre_item=0,In_item=0;
    s=CreatS();
	scanf("%d",&N);
	getchar();//吸收缓冲字符
    int in[N],pre[N];
	for(i=0;i<2*N;i++)//栈的操作是元素的两倍push和pop
	{
		scanf("%s",c);
		if(strcmp(c,"Push")==0)//进行push操作
		{
			scanf("%d",&e);
			pre[pre_item++]=e;//存入先序遍历
			push(s,e);
		}
		else
		{
			in[In_item++]=pop(s);//存入中序遍历
		}
	}
	BT=BuildTree(pre,in,N);//建造树
	PostOrderTravel(BT,BT->data);//后序遍历
	return 0;
}

首先是简单的栈的操作集:

Stack CreatS()
{
	Stack s;
	s=(Stack)malloc(sizeof(struct stack));
	s->next=NULL;
	return s;
}
void push(Stack s,int item)
{
	if (s==NULL)
		s=CreatS();
	Stack t;
	t=(Stack)malloc(sizeof(struct stack));
	t->data=item;
	t->next=s->next;
	s->next=t;
	return;
}
int pop(Stack s)
{
	if(s->next==NULL||s==NULL)
	{
		printf("栈为空,无法抛出元素!");
		return 0;
	}
	Stack cell;
	int m;
	cell=(Stack)malloc(sizeof(struct stack));
	cell=s->next;
	s->next=cell->next;
	m=cell->data;
	free(cell);
	return m;
}

创造一个树节点:

BinTree CreatTNode()
{
	BinTree t;
	t=(BinTree)malloc(sizeof(struct TreeNode));
	t->data=0;
	t->left=t->right=NULL;
	return t;
}

对于建造树这一块,我希望大家能够好好理解:

BinTree BuildTree(int *pre,int *in,int N)
{
	BinTree BT;
    ElementType root;
    int LeftNum, RightNum, flag, i;
    int Left_pre[N], Right_pre[N], Left_in[N], Right_in[N];//定义左前遍历,左中遍历,右前遍历,右中遍历
    if(N==1)//只有一个结点
    {
        BT = CreatTNode();
        BT->data = pre[0];
        BT->left = NULL;
        BT->right = NULL;
        return BT;
    }
    else if(N == 0)
        return NULL;//树为空直接返回
    else{//树不为空,有两个及以上的节点
        root = pre[0];//根节点为先序数组的第一个元素
        BT = CreatTNode();
        BT->data = root;
        flag = LeftNum = RightNum = 0;
        for(i=0;i<N;i++)
        {
            if(in[i]!=root)//先找到中序遍历的根节点在哪里
            {
                if(flag)//开始flag为0,查找根节点的左子树,当查找完设置flag为1,此时开始查找根节点的右子树
                {
                    Right_in[RightNum++] = in[i];//赋值的同时计算右子树元素的数量
                }
                else
                {
                    Left_in[LeftNum++] = in[i];//赋值的同时计算左子树元素的数量
                }
            }
            else
            {
                flag = 1;
            }
        }
        for(i=0;i<LeftNum;i++)//左子树元素数量
            Left_pre[i] = pre[i+1];//从根节点之后进行计算
        for(i=0;i<RightNum;i++)
            Right_pre[i] = pre[LeftNum+i+1];//从根节点加上左子树的元素数量之后进行计算
        BT->left = BuildTree(Left_pre,Left_in,LeftNum);//递归建立左子树
        BT->right = BuildTree(Right_pre,Right_in,RightNum);//递归建立右子树
        return BT;
    }
}

当做完这一步的时候,我想大家已经轻松许多了
关于树的后序遍历,我们应该能做出来了

void PostOrderTravel(BinTree BT,int root)
{
	if(BT->left)//先左
	{
		PostOrderTravel(BT->left,root);
	}
	if(BT->right)//再右
	{
		PostOrderTravel(BT->right,root);
	}
	if(BT->data==root)//最后根
	{
		printf("%d",BT->data);//最后输出根节点
	}
	else
	{
		printf("%d ",BT->data);//不是树的总根我们就再打印元素加空格
	}
}

总的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 30
typedef struct stack *PtrToSNode;
typedef PtrToSNode Stack;
typedef int ElementType;
struct stack
{
	int data;
	PtrToSNode next;
};
struct TreeNode
{
	int data;
	struct TreeNode *left;
	struct TreeNode *right;
};
typedef struct TreeNode *BinTree;

BinTree BuildTree(int *pre, int *in, int N);
BinTree CreateTNode();
Stack CreatS();
void push(Stack s,ElementType e);
ElementType pop(Stack s);
void PostOrderTravel(BinTree BT,int root);

int main()
{
	BinTree BT;
	Stack s;
	char c[5];
	int e,i;
	int N;
	int pre_item=0,In_item=0;
    s=CreatS();
	scanf("%d",&N);
	getchar();
    int in[N],pre[N];
	for(i=0;i<2*N;i++)
	{
		scanf("%s",c);
		if(strcmp(c,"Push")==0)
		{
			scanf("%d",&e);
			pre[pre_item++]=e;
			push(s,e);
		}
		else
		{
			in[In_item++]=pop(s);
		}
	}
	BT=BuildTree(pre,in,N);
	PostOrderTravel(BT,BT->data);
	return 0;
}
Stack CreatS()
{
	Stack s;
	s=(Stack)malloc(sizeof(struct stack));
	s->next=NULL;
	return s;
}
BinTree CreatTNode()
{
	BinTree t;
	t=(BinTree)malloc(sizeof(struct TreeNode));
	t->data=0;
	t->left=t->right=NULL;
	return t;
}
void push(Stack s,int item)
{
	if (s==NULL)
		s=CreatS();
	Stack t;
	t=(Stack)malloc(sizeof(struct stack));
	t->data=item;
	t->next=s->next;
	s->next=t;
	return;
}
int pop(Stack s)
{
	if(s->next==NULL||s==NULL)
	{
		printf("栈为空,无法抛出元素!");
		return 0;
	}
	Stack cell;
	int m;
	cell=(Stack)malloc(sizeof(struct stack));
	cell=s->next;
	s->next=cell->next;
	m=cell->data;
	free(cell);
	return m;
}
BinTree BuildTree(int *pre,int *in,int N)
{
	BinTree BT;
    ElementType root;
    int LeftNum, RightNum, flag, i;
    int Left_pre[N], Right_pre[N], Left_in[N], Right_in[N];
    if(N==1)
    {
        BT = CreatTNode();
        BT->data = pre[0];
        BT->left = NULL;
        BT->right = NULL;
        return BT;
    }
    else if(N == 0)
        return NULL;
    else{
        root = pre[0];
        BT = CreatTNode();
        BT->data = root;
        flag = LeftNum = RightNum = 0;
        for(i=0;i<N;i++)
        {
            if(in[i]!=root)
            {
                if(flag)
                {
                    Right_in[RightNum++] = in[i];
                }
                else
                {
                    Left_in[LeftNum++] = in[i];
                }
            }
            else
            {
                flag = 1;
            }
        }
        for(i=0;i<LeftNum;i++)
            Left_pre[i] = pre[i+1];
        for(i=0;i<RightNum;i++)
            Right_pre[i] = pre[LeftNum+i+1];
        BT->left = BuildTree(Left_pre,Left_in,LeftNum);
        BT->right = BuildTree(Right_pre,Right_in,RightNum);
        return BT;
    }
}
void PostOrderTravel(BinTree BT,int root)
{
	if(BT->left)
	{
		PostOrderTravel(BT->left,root);
	}
	if(BT->right)
	{
		PostOrderTravel(BT->right,root);
	}
	if(BT->data==root)
	{
		printf("%d",BT->data);
	}
	else
	{
		printf("%d ",BT->data);
	}
}
  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值