#ifndef STACK_H_INCLUDED #define STACK_H_INCLUDED #define MAX 20 typedef struct tnode { char data; struct tnode *lchild; struct tnode *rchild; int rvisit; //rvisit==1表示该节点在后序遍历时已被访问过 }TNode,*BTree; typedef struct snode { int top; int array[MAX]; }AStack; typedef struct snode1 { int top; BTree pointer[MAX]; }PStack; int seek(char ch,char *a) { int i; for(i=0;i<strlen(a);i++) { if(a[i]==ch) return i; } return 0; } void a_push(AStack *A,int n) { A->array[++(A->top)]=n; } void p_push(PStack *P,BTree bt) { P->pointer[++(P->top)]=bt; } BTree get(PStack *P) { return P->pointer[P->top]; } void a_pop(AStack *A) { A->top--; } void p_pop(PStack *P) { P->top--; } #endif // STACK_H_INCLUDED
/* 1. 本程序中首先需定义二叉树的节点类型,节点为一个含有数据与和指针域的结构体。 2. 其次,本程序中需要用两个栈,一个用来存放指针,一个用来存放数组元素的下标。 3. 主程序中,分别输入两个字符串,作为二叉树的先序和中序序列; 两个子函数分别实现创建二叉树和后序遍历输出二叉树的功能。而在子函数中还调用了例如出栈入栈等子函数。*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "stack.h" void CreateBiTree(BTree *root,char pre[],char in[],AStack *A,PStack *P) { char *tag=pre; BTree bt; BTree q,r; int num; *root=(BTree)malloc(sizeof(TNode)); (*root)->data=*tag; (*root)->lchild=NULL; (*root)->rchild=NULL; (*root)->rvisit=0; bt=*root; num=seek(*tag,in); a_push(A,num); p_push(P,bt); while(*++tag!='\0') { num=seek(*tag,in); bt=(BTree)malloc(sizeof(TNode)); bt->data=*tag; bt->lchild=bt->rchild=NULL; bt->rvisit=0; if(num<A->array[A->top]) { q=get(P); q->lchild=bt; a_push(A,num); p_push(P,bt); } else if(num>A->array[A->top]) { while(A->top!=-1&&num>A->array[A->top]) { r=P->pointer[P->top]; p_pop(P); a_pop(A); } r->rchild=bt; a_push(A,num); p_push(P,bt); } } } void visit(BTree p) { p->rvisit=1; printf("%c",p->data); } void LastOrderTraverse(BTree bt,PStack *P) { //首先从根节点一直往左下方走,一直走到头将路径上的每一个节点入栈 BTree p,st; p=bt; while(bt) { p_push(P,bt); bt=bt->lchild; } //然后进入循环体 while(P->top!=-1) //只要栈非空 { st=get(P);//st是栈顶节点 /*注意,任意一个结点N,只要他有左孩子,则在N入栈之后, N的左孩子必然也跟着入栈了(这个体现在算法的后半部分), 所以当我们拿到栈顶元素的时候,可以确信这个元素要么没有左孩子, 要么其左孩子已经被访问过,所以此时我们就不关心它的左孩子了,我们只关心其右孩子。*/ if(!st->rchild||st->rvisit) { visit(st); p_pop(P); } else //若它的右孩子存在且rvisited为0,说明以前还没有动过它的右孩子,于是就去处理一下其右孩子。 { //此时我们要从其右孩子结点开始一直往左下方走,直至走到尽头,将这条路径上的所有结点都入栈。 /*当然,入栈之前要先将该结点的rvisited设成1,因为其右孩子的入栈意味着它的右孩子必将先于它被访问(这很好理解, 因为我们总是从栈顶取出元素来进行visit)。由此可知,下一次该元素再处于栈顶时,其右孩子必然已被visit过了,所以此处可以将rvisited设置为1。*/ st->rvisit=1; //往左下方走到尽头,将路径上所有元素入栈 p=st->rchild; while(p) { p_push(P,p); p=p->lchild; } }//这一轮循环已结束,刚刚入栈的那些结点我们不必管它了,下一轮循环会将这些结点照顾的很好。 } } int main() { char pre[MAX],in[MAX]; AStack A; PStack P; BTree root=NULL; //注意这里不能定义成BTree *root;因为这里root没有指向任何正确内存空间 A.top=-1; P.top=-1; printf("连续输入先序序列\n"); scanf("%s",pre); printf("连续输入中序序列\n"); scanf("%s",in); CreateBiTree(&root,pre,in,&A,&P); printf("后序输出:"); P.top=-1; LastOrderTraverse(root,&P); return 0; }
由前序和中序遍历建立二叉树并后序遍历输出二叉树
最新推荐文章于 2022-12-15 16:42:57 发布