/*---------------------------------------------------------------------------------------------------------------------
本题一般的想法可以根据堆栈的操作先将树建起来,然后在对树进行后序遍历,这种方法不仅思维简单,而且出错率很低,
不失为一种好的方法。
但此处我们还是尝试一种新的方法,逼格更高,当然,疏忽也会使调试过程非常的痛苦。。。。
思路如下:中序遍历和后序遍历的区别只在于右子树和根节点谁先被访问,而左子树是没有疑问的,不论哪种方法,都是
第一个被访问,因此对于中序遍历的堆栈操作,想要把它改为后序遍历,只需要把对根节点(相对概念,即子
树的根节点也算根节点)的访问,或者说对根节点的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;
}
1086. Tree Traversals Again (25)
最新推荐文章于 2021-02-26 14:07:35 发布