1086. Tree Traversals Again (25)

来源:互联网 发布:人口数据怎么查 编辑:程序博客网 时间:2024/05/21 15:00
/*---------------------------------------------------------------------------------------------------------------------     本题一般的想法可以根据堆栈的操作先将树建起来,然后在对树进行后序遍历,这种方法不仅思维简单,而且出错率很低, 不失为一种好的方法。     但此处我们还是尝试一种新的方法,逼格更高,当然,疏忽也会使调试过程非常的痛苦。。。。     思路如下:中序遍历和后序遍历的区别只在于右子树和根节点谁先被访问,而左子树是没有疑问的,不论哪种方法,都是               第一个被访问,因此对于中序遍历的堆栈操作,想要把它改为后序遍历,只需要把对根节点(相对概念,即子       树的根节点也算根节点)的访问,或者说对根节点的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
原创粉丝点击