二叉树的实现以及递归遍历的精确模拟

来源:互联网 发布:新网域名怎么转到万网 编辑:程序博客网 时间:2024/06/03 23:44

对于一个二叉树,我们来精确模拟他的递归遍历过程

后序递归遍历的代码如下:

void posttravel(BinTree t){        if(!t){        posttravel(t->left);        posttravel(t->right);        printf("%c "t->data);    }}
我们知道,递归遍历要借助堆栈,并且前序、中序、后序遍历经过节点的次序是一样的,不同的是在不同的时刻访问他们(即打印出来),对于下面的一颗二叉树,我们按照上面的递归代码走一遍


首先,先将A入栈(A并没有执行完,需要先保存起来),

栈中是这样:

A |

执行posttravel(t->left), 

A | B

执行posttravel(t->left), 

A | B | D

执行posttravel(t->left)

A | B | D | NULL;

由于此时的t = NULL. 所以退出posttravel(t->left), 退到上一层,D的左子树执行完了

D先出栈再进栈, t = D,执行posttravel(t->right)

A | B | D | F 

由于F的左右子树都空,就不详述了,D最后出栈,返回上一层, t = D,此时D的左右子树都已经执行完了,D出栈

从D我们可以看到,每个元素都是两次进栈,两次入栈的。第一次遇到D,D第一次入栈,遍历完他的左子树后,D第一次出栈,要遍历他的右子树前,D第二次入栈,遍历完他的右子树后,D第二次出栈

一下的过程相同,有兴趣可以自己走一遍。

下面我们就根据这个过程用非递归方式精确模拟遍历二叉树的过程,注意,这里的遍历单单指遍历二叉树的每个节点,并不是要访问(打印)它,我们要知道,无论哪种遍历方式,走过的路线是一样的,只是打印的时间不同而已.


enum State{ start, return_from_left, return_from_right// 访问左子树、右子树前都要经过根节点,我们以这两次“经过”为标准,将根节点划分为访问了自己,访问完左子树,访问完// 右子树,即过程是:第一次经过自己->访问左子树->第二次经过自己->访问右子树-第三次经过自己(返回上层)};typedef struct StackElem{enum State state; // 节点状态 BinTree t; // 节点 }StackElem;void postorder(BinTree t){// if(!t) return;StackElem item = {start, t}; // 根节点 stack s = createstack(MAX); // 遍历要借助堆栈实现 while(1){ // 退出条件是所有节点都遍历完(每个节点两进两出) if(item.t){if(item.state == start){ // 遍历左子树push(s, item);item.t = item.t->left;item.state = start; }else if(item.state == return_from_left){ // 遍历右子树push(s, item);item.t = item.t->right;item.state = start;}else{// 返回上一层// 左(右)子树遍历完后返回他的根节点(上一层) if(!isempty(s)){item = pop(s);item.state++;}else{break;}}}else{// 当前为空的话,也要返回上一层 if(!isempty(s)){item = pop(s);item.state++;}else{break;}}}return;}

下面是一个后序遍历的具体实现:

#include<stdio.h>#include<stdlib.h>#include<stdbool.h>#define ElementType char#define MAX 50enum State{ start, return_from_left, return_from_right// 访问左子树、右子树前都要经过根节点,我们以这两次“经过”为标准,将根节点划分为访问了自己,访问完左子树,访问完// 右子树,即过程是:第一次经过自己->访问左子树->第二次经过自己->访问右子树-第三次经过自己(返回上层)};typedef struct TNode *BinTree;struct TNode{ElementType data;struct TNode *left;struct TNode *right;};typedef struct StackElem{enum State state;BinTree t;}StackElem;typedef struct Stack{StackElem *data;int MAXSIZE;int top;} *stack;/*******************************/BinTree createtree(BinTree t, bool isroot);stack createstack(int max);void push(stack s, StackElem se);StackElem pop(stack s);int isempty(stack s);void postorder(BinTree t);BinTree createtree(BinTree t, bool isroot);void freetree(BinTree t);/********************************/int main(){BinTree t;t = createtree(t, true);postorder(t);freetree(t);return 0;}// 创建空栈stack createstack(int max){stack s = (stack)malloc(sizeof(struct Stack));s->data = (StackElem *)malloc(sizeof(StackElem) *max);s->MAXSIZE = max;s->top = -1;return s;}// 进栈void push(stack s, StackElem se){if(s->top+1 == s->MAXSIZE)return;s->data[++(s->top)] = se;}// 出栈StackElem pop(stack s){StackElem tmp = s->data[s->top];--s->top;return tmp;}// 判空int isempty(stack s){return s->top == -1;}// 后序遍历void postorder(BinTree t){// if(!t) return;StackElem item = {start, t};stack s = createstack(MAX);while(1){if(item.t){if(item.state == start){ // 遍历左子树push(s, item);item.t = item.t->left;item.state = start;}else if(item.state == return_from_left){ // 遍历右子树push(s, item);item.t = item.t->right;item.state = start;}else{// 返回上一层printf("%c ", item.t->data);if(!isempty(s)){item = pop(s);item.state++;}else{break;}}}else{if(!isempty(s)){item = pop(s);item.state++;}else{break;}}}return;}// 建立二叉树BinTree createtree(BinTree t, bool isroot){ElementType data;if(isroot){printf("root is:");}fflush(stdin);scanf("%c", &data);    fflush(stdin);if(data != '#'){        isroot = false;t = (BinTree )malloc(sizeof(struct TNode));t->data = data;t->left = NULL; t->right = NULL;printf("%c s left child is : ", t->data);t->left = createtree(t->left, isroot);printf("%c s right child is : ", t->data);t->right = createtree(t->right, isroot);}return t;}// 释放二叉树void freetree(BinTree t){if(!t){freetree(t->left);freetree(t->right);free(t);}return;}


阅读全文
0 0
原创粉丝点击