二叉树遍历(递归/非递归实现)
1. tree traversal
先序preorder:节点,左孩子,右孩子
中序inorder:左孩子,节点,右孩子
后序postorder:左孩子,右孩子,节点
层序levelorder:按照节点从上到下,从左到右的顺序访问
2. 程序实现-前期
- 二叉树定义
typedef char eletype;//二叉树结点信息类型 typedef struct BiTNode//二叉树结点类型 { bool flog; //为后序遍历准备,也可以不用,后面详述 struct BiTNode *lchild,*rchild; eletype data; }BiTNode; typedef BiTNode *elemtype;//elemtype声明为指针类型
- 栈的相关定义
#define STACK_INIT_SIZE 100//栈初始分配的空间数 #define STACKINCREAMENT 10//栈空间不够时增加的空间数 typedef struct stack//栈的存储类型,采用动态分配 { elemtype *base; elemtype *top; int stacksize; }sqstack; sqstack *initstack()//创建栈 { sqstack *s; if (!(s = (sqstack *)malloc(sizeof(sqstack))))exit(-1); s->base = (elemtype *)malloc(STACK_INIT_SIZE*sizeof(elemtype));//初始化为栈分配STACK_INIT_SIZE个elemtype类型的空间 if (!s->base)//分配空间失败 { exit(-2); printf("栈空间分配失败!\n"); } if (s->base)//分配空间成功 printf("栈空间分配成功!\n"); s->top = s->base;//初始化栈的头尾指针 s->stacksize = STACK_INIT_SIZE; return s; } void push(sqstack *s,elemtype e)//压栈,e要是一个地址 { if (s->top-s->base>=s->stacksize)//栈满 { s->base = (elemtype *)realloc(s->base,(s->stacksize+STACKINCREAMENT)*sizeof(elemtype));//栈满时增加空间 if (!s->base)//增加分配空间失败 exit(-2); s->stacksize += STACKINCREAMENT; } *(s->top) = e; s->top++; } elemtype pop1(sqstack *s)//出栈1,返回的e为栈顶元素是一个地址 { elemtype e; if (s->top == s->base)return 0;//栈空时返回 s->top--; e = *(s->top); return e; } int stackempty(sqstack *s)//判断栈空,栈空返回1,否则返回0 { if (s->base == s->top)return 1; else return 0; }
- 先序递归法建树(即输入二叉树)
- 方法1
BiTNode *CreateBiTree()//先序递归法建树 { char x; BiTNode *t; scanf("%c",&x); //x=getchar(); if (x == ' ')t = NULL; else { if (!(t = (BiTNode *)malloc(sizeof(BiTNode))))exit(-1); t->data = x;//建立节点 t->flog = false; t->lchild = CreateBiTree();//建左子树 t->rchild = CreateBiTree();//建右子树 } return t; }
-
- 方法2
BiTNode* BT_MakeNode(eletype target) { BiTNode* pNode = (BiTNode*) malloc(sizeof(BiTNode)); assert( NULL != pNode ); pNode->data = target; pNode->lchild = NULL; pNode->rchild = NULL; pNode->flog =false; return pNode; } BiTNode* CreateBiTree1(eletype target, elemtype* ppTree) { BiTNode* Node; assert( NULL != ppTree); Node = *ppTree; if (NULL == Node) { return *ppTree = BT_MakeNode(target); } if (Node->data == target) //不允许出现相同的元素 { return NULL; } else if (Node->data > target) //向左 { return CreateBiTree1(target, &Node->lchild); } else { return CreateBiTree1(target, &Node->rchild); } } void getNode(BiTNode* node) //对遍历出的节点的操作 { printf("%d ",node->data); }
- 对节点的操作
//void (*visit)(BiTNode*) void getNode(BiTNode* node) //对遍历出的节点的操作 { printf("%d ",node->data); }
3. 程序实现-核心
- 非递归实现
PreOider
void PreOrder(BiTNode* t,void (*visit)(BiTNode*)) //前序遍历二叉树非递归算法 { sqstack* s; BiTNode* p; s=initstack(); //初始化栈 p=t; printf("前序遍历二叉树,字符序列为:\n"); push(s,p); while (!stackempty(s)) { p=pop1(s); (*visit)(p); if (p->rchild!=NULL) { push(s,p->rchild); } if (p->lchild!=NULL) { push(s,p->lchild); } } printf("\n"); }
InOrder
void InOrder(BiTNode *t,void (*visit)(BiTNode*))//中序遍历二叉树非递归算法 { sqstack *s; BiTNode *p; s = initstack();//初始化栈 p = t; printf("中序遍历二叉树,字符序列为:\n"); while (p||!stackempty(s)) { while (p)//找最左结点 { push(s,p); p = p->lchild;//p指针顺lchild而下 } p = pop1(s);//栈顶元素出栈以访问最左结点 (*visit)(p);//访问最左结点 p = p->rchild; } printf("\n"); }
PostOrder_1(需要标志位)
//需要标志位flog void PostOrder_1(BiTNode* t,void (*visit)(BiTNode*)) { sqstack *s; BiTNode* p; s = initstack();//初始化栈 p=t; printf("后序遍历二叉树,字符序列为:\n"); while (p||!stackempty(s)) { while (p)//找最左结点 { push(s,p); p = p->lchild;//p指针顺lchild而下 } s->top--; p=*(s->top); s->top++; //p=pop1(s); //push(s,p); if (!p->rchild||p->flog) { p=pop1(s); (*visit)(p); p=NULL; //指向空,防止下次循环中while(p)的循环出错 } else { p->flog=true; p=p->rchild; } } printf("\n"); }
PostOrder_2
//记住一点:你输出的节点同时也是上一级(如果存在的话)的右孩子。 void PostOrder_2(BiTNode* root,void (*visit)(BiTNode*)) { sqstack* s; BiTNode* p; s=initstack(); p=NULL; while (root||!stackempty(s)) { if (root) //寻找右节点 { push(s,root); root = root->lchild; } else { s->top--; root=*(s->top); s->top++; if (root->rchild!=NULL && p!=root->rchild) { //如果这个节点标记过,就证明root节点的右孩子已经遍历过了,不要重复 root=root->rchild; } else { s->top--; p=root=*(s->top); //标记这个节点 s->top++; (*visit)(p); pop1(s); root=NULL; } } } printf("\n"); }
- 层序遍历LevelOrder
我们如果仔细揣摩,把preorder中的栈换成队列就得到了层序遍历了(LIFO-->FIFO)。
LevelOrder
void LevelOrder(BiTNode* t,void (*visit)(BiTNode*)) { sqQUEUE* q; BiTNode* p; q=initQUEUE(); //初始化队列 p=t; printf("层序遍历二叉树,字符序列为:\n"); QUEUEput(s,p); while (!QUEUEempty(s)) { p=QUEUEget(s); (*visit)(p); if (p->lchild!=NULL) { QUEUEput(s,p->lchild); } if (p->rchild!=NULL) { QUEUEput(s,p->rchild); } } printf("\n"); }
- 递归实现
以前序遍历为例,递归很简单。若果我们把(*visit)函数的调用移到递归调用中间,就是中序遍历;移到递归调用之后,就成了后序遍历。
traverse
void traverse(BiTNode *t,void (*visit)(BiTNode*)) { if (t==NULL) { return; } (*visit)(t); traverse(t->lchild,getNode); traverse(t->rchild,getNode); }
4. 程序测试
int main() { int i; BiTNode *t=NULL; printf("请输入建树字符序列,以1表示NULL:\n"); t = CreateBiTree(); //注意前序递归法建树的方法 //srand( (unsigned)time( NULL ) ); //for (i=0; i<10; i++) //{ // CreateBiTree1(rand()/100, &t); //} traverse(t,getNode); //递归实现遍历 printf("\n"); PreOrder(t,getNode); InOrder(t,getNode); PostOrder_1(t,getNode); PostOrder_2(t,getNode); return 0; }
本文参考: