1086. Tree Traversals Again (25)

/*---------------------------------------------------------------------------------------------------------------------
     本题一般的想法可以根据堆栈的操作先将树建起来,然后在对树进行后序遍历,这种方法不仅思维简单,而且出错率很低,
	 不失为一种好的方法。
     但此处我们还是尝试一种新的方法,逼格更高,当然,疏忽也会使调试过程非常的痛苦。。。。
     思路如下:中序遍历和后序遍历的区别只在于右子树和根节点谁先被访问,而左子树是没有疑问的,不论哪种方法,都是
               第一个被访问,因此对于中序遍历的堆栈操作,想要把它改为后序遍历,只需要把对根节点(相对概念,即子
	       树的根节点也算根节点)的访问,或者说对根节点的pop操作改在对右子树所有节点的pop之后便大功告成了。
	       我们只在原输入的基础上,调换(或说调整)一部分pop或push操作的位置,就可以把中序遍历的堆栈操作,改
	       成后序遍历的堆栈操作,然后根据给出的堆栈操作依次写出数据,就是后序遍历的结果。
-----------------------------------------------------------------------------------------------------------------------*/
#include<stdio.h>  
#include<stdlib.h>
#include<string.h>

typedef struct Node* node;
typedef struct Stack* stack;

struct Node{
	char s[5];
	int num;
	node next;
};
struct Stack{
	node nodee;
	stack next;
};
stack down,up;

node pop();
void push(node this_node);

int main(){
	int i,amount;
	int key=0;
	down = (stack)malloc(sizeof(struct Stack));
	down->nodee = NULL;
	up = down;
	node header=NULL,tail=NULL,now=NULL,temp = NULL,temp2;
	header = (node)malloc(sizeof(struct Node));
	tail = header ;
	scanf("%d",&amount);
	getchar();
	for(i=1;i<=2*amount;i++){
		tail->next = (node)malloc(sizeof(struct Node));
		tail = tail->next;
		tail->next = NULL;
		scanf("%s",tail->s);
		if(!strcmp(tail->s,"Push"))
			scanf("%d",&tail->num);
	}
	temp = header;
	now = temp->next;
	                     /*---下述循环的功能:将对含有右子树的节点的pop操作的位置都换到其所有右子树pop操作的后面---*/
	while(now){
		/* --------------------------------------------------------------------------------------------------------------
		      如果某一pop语句是一连串pop语句的最后一个,即该pop语句后面是一个push语句,那么,该pop语句一定是对含有
		   右子树的节点的pop,因为在中序遍历的堆栈操作中,对节点pop完以后的下一操作就是对其右子树的根节点的push操
		   作,且这句话的结论是可逆的,即对于任何子树根节点的push操作,一定紧跟在对于其parent的pop操作之后,所以,
		   所有push语句之前的pop语句,都是我们的操作对象。
		----------------------------------------------------------------------------------------------------------------*/
		if(!strcmp(now->s,"Pop") && now->next!=NULL && strcmp(now->next->s,"Pop")){
			key = 1;/*k算是一个平衡值,代表某一pop操作后的push操作次数和pop操作次数的差值*/
			temp->next = temp2 = now->next;
			while(key!=-1&&temp2->next != NULL){     /*--------------------------------------------------------------------
								  k == -1时,说明右子树已经全部遍历完,当然,对于根节点而言,k最小也只能
								  为0,属于特殊情况,因此,通过没有后续操作来判定对右子树的访问已经结束
							       -----------------------------------------------------------------------*/
				temp2 = temp2->next;
				if(!strcmp(temp2->s,"Pop"))key--;
				else key++;
			}
			now->next = temp2->next;
			temp2->next = now;
			now = temp->next;
		}
		/*===============其余情况下,我们都不需要对push,pop操作做调整,因为他们属于后序遍历和中序遍历的相同操作==================*/
		else{
			temp = now;
			now = now->next;
		}
	}
	/*====================================================================================================================
	                      至此,题目中给出的中序遍历方式已经被我们改成了后序遍历的堆栈操作,
					 接下来要进行的就是根据操作,真正模拟出一个堆栈,执行下去就可以得出正确答案
	 ======================================================================================================================*/
	temp = header->next;
	while(temp){
		if(!strcmp(temp->s,"Push"))
			push(temp);
		else if(!strcmp(temp->s,"Pop")){
			now = pop();
			printf("%d",now->num);
			if(temp->next != NULL)
				printf(" ");
		}
		temp = temp->next;
	}
	return 0;
}

void push(node this_node){                  //堆栈没有大小限制,当然,根据题目,最多有30个数据
	stack temp;
	temp = (stack)malloc(sizeof(struct Stack));
	temp->nodee = this_node;
	temp->next = up;
	up = temp;
	return ;
}

node pop(){                                 //会有非法栈操作吗?除非题目出错!因此可以不检查堆栈访问越界的问题
	stack temp;
	node p;
	temp = up;
	up = up->next;
	p = temp->nodee;
	free(temp);
	return p;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值