二叉树的先序、中序、后序 递归与非递归遍历,以及分层遍历

  1. 题目:建立以左右孩子链接结构表示的二叉树,实现二叉树的先序、中序、后序的递归和非递归方式遍历,分层遍历、统计树的高度。
  2. 树结点
struct node{
   	 	char ch;
   	 	struct node *lson, *rson;
	};
  1. 栈结点
struct Stack{
    struct node *loc;
    struct Stack *next;
};

  1. 二叉树建立的函数
    二叉树的建立在逻辑上是按照先根顺序建立的,但是输入数据的时候是一对一对输入,根结点在主函数中输入,然后在函数中一次性输入其左右儿子,若都不为空,则递归调用这个函数,继续输入这个左儿子的左右儿子,右结点也是一样,若是输入‘#’则表示这个结点结束了没有数据,在程序中不占内存,在上一个结点的后序中是NULL。
void InputMyTree(struct node *root, FILE *fp)//二叉树的输入
{    char lef, rig;
    struct node *index = root;
    printf("Please input your lson and rson\n");
    scanf("%c%c", &lef, &rig);
    getchar();
    printf("%c%c\n", lef, rig);
    fprintf(fp , "%c%c", lef, rig);

    if(lef == '#') {
        root->lson = NULL; }
    else {
        //NodesNumber+=1;
        root->lson = (struct node *)malloc(sizeof(struct node));
        root = root->lson;
        root->ch = lef;
        InputMyTree(root, fp); }
    if(rig == '#') {
        index->rson = NULL; }
    else {
        //NodesNumber+=1;
        index->rson = (struct node *)malloc(sizeof(struct node));
        index = index->rson;
        index->ch = rig;
        InputMyTree(index, fp); }
}
  1. 递归式先序遍历二叉树的函数
    递归式先序遍历,得到根结点后访问,然后递归调用这个函数本身,先遍历根的左儿子,若其不为空则访问结点的数据,然后继续调用这个函数,若空则遍历右儿子,若右儿子不为空则访问结点的数据,空则结束函数。
    代码:
void RootFirst1(struct node *root, FILE *fp) //先序遍历:递归
{
    if(root == NULL) {
        return;
    }
    fprintf(fp, "%c", root->ch);
    printf("%c\n", root->ch);
    RootFirst1(root->lson, fp);
    RootFirst1(root->rson, fp);
}
  1. 中序遍历二叉树的函数
    与先序遍历类似,先遍历左儿子,然后输出根结点,然后遍历右儿子,用的是递归调用函数本身的方法。
void RootSecond1(struct node *root, FILE *fp)//中序遍历:递归
{
    if(root->lson != NULL) {
        RootSecond1(root->lson, fp);
    }
    fprintf(fp, "%c", root->ch);
    if(root->rson != NULL) {
        RootSecond1(root->rson, fp);
    }
}
  1. 递归式后序遍历二叉树
    与递归先序遍历类似,只不过是先遍历左右儿子然后访问根结点。
void RootThird1(struct node *root, FILE *fp) //后序遍历:递归
{    if(root->lson != NULL) {
        RootThird1(root->lson, fp);    }
    if(root->rson != NULL) {
        RootThird1(root->rson, fp);    }
    fprintf(fp, "%c", root->ch);
}
  1. 非递归先序遍历二叉树的函数
    非递归先序遍历二叉树用到了栈,定义了一个搜索指针P,在一个while()循环中将用p沿着左儿子的方向从根结点向下搜索,并且将沿途的结点都入栈(包括根结点),顺便进行访问,直到p指向NULL,while()循环结束,再出栈,将栈顶元素给p,然后将p的右儿子,赋值给p,重复以上步骤,便相当于遍历了右儿子,若右儿子为空则while()循环不进行,会直接退栈,向入栈的反方向遍历右儿子。
void RootFirst2(struct node *root, FILE *fp) //先序遍历:非递归
{
    struct Stack *phead = NULL;
    struct node *p = root;
    do {
        while(p != NULL) {
                phead = insert(phead, p); 
                fprintf(fp, "%c", p->ch);//打印根结点数据
                p = p->lson;
        }
        if(phead != NULL) {           
            p = phead->loc;
            phead = phead->next;//退栈
            p = p->rson;//遍历右儿子            
        }
    } while(p != NULL || phead != NULL);//判断p=nil AND 栈空
}
  1. 非递归中序遍历二叉树的函数
    与非递归先序遍历二叉树非常相似,只是改变了访问结点的时机,因为是先遍历左儿子再遍历右儿子的顺序,所以访问节点数据的时机只在出栈的时候,在第一个while()循环结束时,首先将左儿子的数据(当时是栈顶)访问,然后退栈,遍历右儿子,重复,找到一个没有左右儿子的结点的时候,访问结点然后退栈,因为右儿子为空,所以会再次退栈访问根,然后再次判断右儿子,访问根,这样,直到搜索指针和栈都为空,整个循环结束,函数也结束。
void RootSecond2(struct node *root, FILE *fp)//中序遍历:非递归
{    struct Stack *phead = NULL;  
    struct node *p = root;
    do {
        while(p != NULL) {               
                phead = insert(phead, p);               
                p = p->lson;
        }       
        if(phead != NULL) {
            fprintf(fp, "%c" , phead->loc->ch);//访问栈顶元素
            p = phead->loc;
            phead = phead->next;//退栈
            p = p->rson;//回到do_while开头遍历右儿子           
        }            
    } while(p != NULL || phead != NULL);//判断p=nil AND 栈空
}
  1. 非递归后序遍历二叉树
    非递归后序遍历比前两个非递归的复杂,因为要先访问左右儿子,所以,在搜索指针指到二叉树叶子的下一个,即NULL的时候,要退栈访问左儿子,但是此时不能直接再次遍历右儿子,而是要在遍历结束时加一个判断,若是当前结点右儿子为空或者右儿子已经遍历过,才能退栈。
    代码:
void RootThird2(struct node *root, FILE *fp) //后序遍历:非递归
{    struct Stack *phead = NULL;
    struct node *p = root, *temp, *index;
    while(p != NULL || phead != NULL){
        while(p != NULL) {
                phead = insert(phead, p);
                index = p;
                p = p->lson;
        }
        if(phead != NULL) {
            p = phead->loc;//栈顶给P
            if(p->rson == NULL || temp == p->rson) {
                ///printf("Anode:%c\n", p->ch);
                fprintf(fp, "%c", p->ch);
                phead = phead->next;//退栈
                temp = p;
                p = NULL;
            }  else  {
                p = p->rson;//遍历右儿子
            }          
        }
    } 
}
  1. 分层遍历二叉树
    这个函数用到了队列,在循环开始前就将根结点入队,循环开始,将队列开头的结点给指针P,队首指针后移,访问P指向的数据,然后将P非空的左右儿子入队,结束本次循环,就相当于根节点下面的“一层”入队了,然后第二、三次循环,将第二层的数据访问,并且将第三层的结点入队……这样循环直到队列为空结束,就将二叉树分层遍历结束了。
void level(struct node *root, FILE *fp)//分层遍历
{
    struct node *p = root;
    struct Stack *lead = (struct Stack *)malloc(sizeof(struct Stack)),
                 *tail = (struct Stack *)malloc(sizeof(struct Stack));
    lead->next = tail;
    tail->loc  = NULL;
    tail->next = NULL;
    //
    lead->loc = root;
    while(lead->loc != NULL) {
        printf("Aqueue\n");
        p = lead->loc;
        fprintf(fp, "%c", p->ch);

        if(p->lson != NULL) {
            tail->loc = p->lson;//左儿子入队
            tail->next = (struct Stack *)malloc(sizeof(struct Stack));
            tail = tail->next;
            tail->loc = NULL;
            tail->next = NULL;
        }
        if(p->rson != NULL) {
            tail->loc = p->rson;//右儿子入队
            tail->next = (struct Stack *)malloc(sizeof(struct Stack));
            tail = tail->next;
            tail->loc = NULL;
            tail->next = NULL;
        }
        lead = lead->next;//出队
    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值