二叉树遍历的递归与非递归写法_C语言

巧了我就是萌 提交于 2020-02-03 12:11:46

前言

二叉树的三种遍历的递归写法,只要理解思想,几行代码就可以完成。可是非递归写法却很不容易。这里特地总结下,透彻解析它们的非递归写法。其中,中序遍历的非递归写法最简单,后序遍历最难。

中序遍历的非递归写法

非递归算法,必然要用到栈(可参考完整代码中栈的实现)。这里着重讲下中序遍历的写法。

void InorderTraversal(BinTree BT)
{
    BinTree T;
    Stack TreeStack;
    TreeStack = CreateStack();

    T = BT;
    while (T || !IsEmpty(TreeStack)){//注意循环结束的条件
        while (T){   				//将左子树一口气全部入栈
            Push(TreeStack,T);		
            T = T->Left;			
        }
        T = Pop(TreeStack);			// 退出循环时,T为空,即再无左子树
        printf("%d  ", T->Data);	//此时,打印该节点值
        T = T->Right;				//而后,转向右子树,若该节点为叶子节点,
        							//则T仍为空,下一次循环直接出栈,
        							//此处巧妙将叶子节点与常规节点的代码统一
    }
}

后序遍历的非递归写法

后序遍历需要将父节点入栈两次,第二次出栈时才打印,因此需要做标记。代码在中序遍历基础上修改,理解了中序遍历,下面这段代码也不难理解。

void PostOrderTraversal(BinTree BT)
{
    BinTree T;
    Stack TreeStack;
    TreeStack = CreateStack();

    T = BT;
    while (T || !IsEmpty(TreeStack)){
        while (T){                          //遍历左子树
            Push(TreeStack,T);
            T = T->Left;
        }
        T = Pop(TreeStack);
        if (T->flag != 54321){              //54321魔术字,表示右子树已入栈
            T->flag = 54321; 
            Push(TreeStack,T);              //再次入栈,并遍历右子树
            T = T->Right;
        } else {
            printf("%d  ", T->Data);
            T = NULL;                       //巧妙利用NULL在下一次循环时引向右子树
        }
    }
}

完整代码

/* 树的遍历 */
#include "stdio.h"
#include "stdbool.h"
#include <stdlib.h>

/* type define for Tree */
typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{           /* 树结点定义 */
    int Data;           /* 结点数据 */
    BinTree Left;       /* 指向左子树 */
    BinTree Right;      /* 指向右子树 */
    int flag;           /* 用于后序遍历,入栈标记 */
};

/* type define for stack */
typedef BinTree ElementType;
typedef struct SNode *PtrToSNode;
struct SNode {
    ElementType Data;
    PtrToSNode Next;
};
typedef PtrToSNode Stack;

Stack CreateStack( ) 
{ /* 构建一个堆栈的头结点,返回该结点指针 */
    Stack S;
 
    S = (Stack)malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}
 
bool IsEmpty ( Stack S )
{ /* 判断堆栈S是否为空,若是返回true;否则返回false */
    return ( S->Next == NULL );
}
 
bool Push( Stack S, ElementType X )
{ /* 将元素X压入堆栈S */
    PtrToSNode TmpCell;
 
    TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
    TmpCell->Data = X;
    TmpCell->Next = S->Next;
    S->Next = TmpCell;
    return true;
}
 
ElementType Pop( Stack S )  
{ /* 删除并返回堆栈S的栈顶元素 */
    PtrToSNode FirstCell;
    ElementType TopElem;
 
    if( IsEmpty(S) ) {
        printf("堆栈空"); 
        return NULL;
    }
    else {
        FirstCell = S->Next; 
        TopElem = FirstCell->Data;
        S->Next = FirstCell->Next;
        free(FirstCell);
        return TopElem;
    }
}

BinTree TreeCreat()    //构建待验证的树
{
    BinTree T,BT;
    BT = (BinTree)malloc(sizeof(struct TNode));
    /* A */
    T = BT;             
    T->Data = 1;
    T->Left = (BinTree)malloc(sizeof(struct TNode));
    T->Right = (BinTree)malloc(sizeof(struct TNode));
    /* B */
    T = BT->Left;       
    T->Data = 2;        
    T->Left = (BinTree)malloc(sizeof(struct TNode));
    T->Right = (BinTree)malloc(sizeof(struct TNode));
    /* C */
    T = BT->Right;      
    T->Data = 3;
    T->Left = (BinTree)malloc(sizeof(struct TNode));
    T->Right = (BinTree)malloc(sizeof(struct TNode));
    /* D */
    T = BT->Left->Left; 
    T->Data = 4;
    T->Left = NULL;
    T->Right = NULL;
    /* E */
    T = BT->Left->Right; 
    T->Data = 5;
    T->Left = (BinTree)malloc(sizeof(struct TNode));
    T->Right = NULL;
    /* F */
    T = BT->Right->Left; 
    T->Data = 6;
    T->Left = NULL;
    T->Right = (BinTree)malloc(sizeof(struct TNode)); 
    /* G */
    T = BT->Right->Right; 
    T->Data = 7;
    T->Left = NULL;
    T->Right = NULL;
    /* H */
    T = BT->Left->Right->Left; 
    T->Data = 8;
    T->Left = NULL;
    T->Right = NULL;    
    /* I */
    T = BT->Right->Left->Right; 
    T->Data = 9;
    T->Left = NULL;
    T->Right = NULL;

    return BT;
}
void InorderTraversal(BinTree BT)
{
    BinTree T;
    Stack TreeStack;
    TreeStack = CreateStack();

    T = BT;
    while (T || !IsEmpty(TreeStack)){
        while (T){
            Push(TreeStack,T);
            T = T->Left;
        }
        T = Pop(TreeStack);
        printf("%d  ", T->Data);
        T = T->Right;
    }

}
void PreOrderTraversal(BinTree BT)
{
    BinTree T;
    Stack TreeStack;
    TreeStack = CreateStack();

    T = BT;
    while (T || !IsEmpty(TreeStack)){
        while (T){
            printf("%d  ", T->Data);
            Push(TreeStack,T);
            T = T->Left;
        }

        T = Pop(TreeStack);
        T = T->Right;
    }

}

void PostOrderTraversal(BinTree BT)
{
    BinTree T;
    Stack TreeStack;
    TreeStack = CreateStack();

    T = BT;
    while (T || !IsEmpty(TreeStack)){
        while (T){                          //遍历左子树
            Push(TreeStack,T);
            T = T->Left;
        }
        T = Pop(TreeStack);
        if (T->flag != 54321){              //54321魔术字,表示右子树已入栈
            T->flag = 54321; 
            Push(TreeStack,T);              //再次入栈,并遍历右子树
            T = T->Right;
        } else {
            printf("%d  ", T->Data);
            T = NULL;                       //巧妙利用NULL在下一次循环时引向右子树
        }
    }
}

void PreOrderTraversal_R(BinTree BT)
{
    if(BT){
        printf("%d  ", BT->Data);
        PreOrderTraversal(BT->Left);
        PreOrderTraversal(BT->Right);
    }
}
void InOrderTraversal_R(BinTree BT)
{
    if(BT){
        InOrderTraversal_R(BT->Left);
        printf("%d  ", BT->Data);
        InOrderTraversal_R(BT->Right);
    }
}
void PostOrderTraversal_R(BinTree BT)
{
    if(BT){
        PostOrderTraversal_R(BT->Left);
        PostOrderTraversal_R(BT->Right);
        printf("%d  ", BT->Data);
    }
}
int main()
{
    BinTree BT = TreeCreat();
    printf("PostOrderTraversal_R:");
    PostOrderTraversal_R(BT);
    printf("\r\n");
    printf("PostOrderTraversal_L:");
    PostOrderTraversal(BT);
    printf("\r\n");
    return 0;
}

代码中构造的树的结构
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!