C语言-数据结构-二叉树的递归遍历和非递归遍历

看了大量网络相关的理论和程序,多数的C++ 写的,这里使用devC++
编程语言 C语言; 整合王道考研答案和理论, 还有小甲鱼的数据结构, 郝斌的数据结构,各有特点吧
最值得研究的还是后序遍历的非递归算法, 当时想了使用flag, 想到了多用一个栈, 想到了很多种方式,最后都以失败告终,经过网络查找,
感谢 https://www.cnblogs.com/rain-lei/p/3705680.html
这里使用的一个栈每个结点两次入栈,解决了后序遍历与父结点遍历的冲突,相信只有仔细思考过这个问题的朋友才会明白多有意思.
话不多说,直接上代码, 复制粘贴可用.

#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#include "string.h"
#include "stdbool.h"

/*  变量声明区  */
typedef char elemType; 


/*    结构体声明    */
typedef struct BitTree{ //树
    elemType data;
    struct BitTree *lChild, *rChild;
    int lTag, rTag; 
}*PBitTree, BitTreeN; 

#define STACK_MAX_SIZE 50
typedef struct Stack{   //栈
    PBitTree data[STACK_MAX_SIZE];
    int top;
}Stack, *PStack; 
/*
    注意 top=-1为空 top=max为满 
*/ 

#define QUEUE_MAX_SIZE 50
typedef struct Queue{   //队列 
    PBitTree data[QUEUE_MAX_SIZE]; 
    int rear,front; 
}Queue, *PQueue; 
/*
    注意 rear=front为空 (rear+1)%max = front为满 
*/


/*  函数声明区  */
//common bit tree

void CreateBieTr_Pre(PBitTree*T);               /*  动态创建先序二叉树  */
/*使用递归方式,判断的输入的字符是否为' ',然后递归&(*T)->lChild,在rChild*/ 

PBitTree CreateBT(void);                        //静态建立二叉树
/*创建结点,在将结点相互关联到一起*/ 

PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn);  
/*将先序和中序合并成先序, 使用遍历算法,
先找到先序的第一个结点,用第一个查找中序的位置,确定好中序中间位置到两端的长度,
作为递归确定左右孩子的参数, 当找不到中点表示为NULL*/ 

//递归遍历 
void visit(elemType ch, int level);  
void PreOrder_Recursion(PBitTree T, int level);  /* 先序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level); /* 中序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level);/* 后序遍历二叉树 */

//非递归遍历 
void InOrder2(PBitTree T);  //使用栈 中序遍历 非递归 
void PreOrder2(PBitTree T);  //使用栈 先序遍历 非递归 
void PostOrder2(PBitTree T);  //使用栈 后序遍历 非递归 
void PostOrder2_2(PBitTree T);  //双次入栈 后序遍历 非递归 
void LevelOrder_from_H_to_L_L_to_R(PBitTree T); //使用队列 层次遍历 非递归  


void main() 
{
    int i; 
    PBitTree T = NULL;
    char val;
    int int_val;
    int level=1; 

    //初始化二叉树1 
//  printf("下面进行动态先序生成二叉树,使用空格作为NULL标记:\n");    
//  CreateBieTr_Pre( &T );

    //初始化二叉树2 
//  T =CreateBT();

    //初始化二叉树3 
    elemType pre[] = "ABCDEF"; 
    elemType  in[] = "CBDAEF"; 
    T = InitBitTree_Pre(pre, 0, 6, in, 0, 6);   


    printf("普通二叉树的前序遍历\n"); PreOrder_Recursion(T, level); 
    printf("普通二叉树的中序遍历\n"); MedOrder_Recursion(T, level); 
    printf("普通二叉树的后序遍历\n"); PostOrder_Recursion(T, level);  

    InOrder2(T); //中序非递归二叉树的遍历 
    PreOrder2(T);
    PostOrder2(T); 
    PostOrder2_2(T);

    LevelOrder_from_H_to_L_L_to_R(T);

    return;
}



/*  函数实现区  */ //---------------------------------------------------------------


//动态 先序创建树 
void CreateBieTr_Pre(PBitTree*T) 
{
    elemType ch;
    scanf("%c",&ch);
    if(' ' == ch) 
    {   
        *T = NULL; 
        return; 
    }
    else
    {
        (*T) = (PBitTree)malloc(sizeof(BitTreeN));
        (*T)->data = ch;
        CreateBieTr_Pre(&(*T)->lChild);
        CreateBieTr_Pre(&(*T)->rChild);
        return;
    }   
}

/*  静态建立二叉树 */ 
PBitTree CreateBT(void)
{   
    PBitTree PA = (PBitTree)malloc(sizeof(BitTreeN)); PA->data = 'A';
    PBitTree PB = (PBitTree)malloc(sizeof(BitTreeN)); PB->data = 'B';
    PBitTree PC = (PBitTree)malloc(sizeof(BitTreeN)); PC->data = 'C';
    PBitTree PD = (PBitTree)malloc(sizeof(BitTreeN)); PD->data = 'D';   
    PBitTree PE = (PBitTree)malloc(sizeof(BitTreeN)); PE->data = 'E';   
    PBitTree PF = (PBitTree)malloc(sizeof(BitTreeN)); PF->data = 'F';   

    PA->lChild = PB; PA->rChild = PE;
    PB->lChild = PC; PB->rChild = PD;   
    PE->lChild = NULL; PE->rChild = PF; 
    PC->lChild = PC->rChild = NULL;
    PD->lChild = PD->rChild = NULL;
    PF->lChild = PF->rChild = NULL;
    return PA;
}
/*  给出先序和中序,求先序的二叉链表 Pre是先序 给出数组中0-n表示的位置 In是中序  */
PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn)
{
//  if()return; 
    PBitTree Root = (PBitTree)malloc(sizeof(BitTreeN));
    Root->data = pre[pre0];
    int i;
    int lLen,rLen; 
    for(i=in0; in[i] != Root->data; i++);   //找到中间值

    lLen = i-in0;  //左子树长度 
    rLen = inn-i;   //右子树长度 

    printf("in0=%d, inn=%d  pr0=%d, pren=%d data  %c  zuo %d zyo  %d \n",pre0, pren, in0, inn,  Root->data,lLen,rLen); 
    if(lLen)
    {

        Root->lChild = InitBitTree_Pre(pre, pre0+1, pre0+lLen, in, in0, in0+lLen-1);//建立左子树 
    }
    else
    {
        Root->lChild = NULL;
    }

    if(rLen)
    {
        Root->rChild = InitBitTree_Pre(pre, pren-rLen+1, pren, in, inn-rLen+1, inn);//建立左子树 
    }
    else
    {
        Root->rChild = NULL;
    }    

    return Root;
}


//-----以下为common Bit Tree的三种遍历----------------------------------------------------------------------------// 

void visit(elemType ch, int level)
{
    printf("树 %c 位于第 %d 层\n", ch, level);
    return;
} 

/* 先序遍历二叉树 */
void PreOrder_Recursion(PBitTree T, int level)
{
    if(NULL != T)  //递归缺点 浪费空间,运行时间长 
    {
        visit(T->data, level);//访问根节点 
        if(NULL != T->lChild) PreOrder_Recursion(T->lChild, level+1);  //先左子树 
        if(NULL != T->rChild) PreOrder_Recursion(T->rChild, level+1);   //后右子树      
    } 
    return;
} 

/* 中序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level)
{
    if(NULL != T)  //递归缺点 浪费空间,运行时间长 
    {
        if(NULL != T->lChild) MedOrder_Recursion(T->lChild, level+1);  //先左子树
        visit(T->data, level);//访问根节点        
        if(NULL != T->rChild) MedOrder_Recursion(T->rChild, level+1);   //后右子树      
    } 
} 

/* 后序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level)
{
    if(NULL != T)  //递归缺点 浪费空间,运行时间长 
    {
        if(NULL != T->lChild) PostOrder_Recursion(T->lChild, level+1);  //先左子树               
        if(NULL != T->rChild) PostOrder_Recursion(T->rChild, level+1);  //后右子树      
        visit(T->data, level);//访问根节点 
    } 
}

/*   普通二叉树 非递归 中序遍历  */
void InOrder2(PBitTree T)
{   
    printf("普通二叉树 非递归 中序遍历:\n");
    PBitTree P = T; //P是遍历指针 
    PStack S = (PStack)malloc(sizeof(Stack));  S->top = -1; //初始化栈

    while( P || ( S->top != -1 ) )  //栈不空 P不空 
    {
        if( P )
        {
            if(S->top != STACK_MAX_SIZE)  //栈不满 
            {
                S->data[ ++S->top ] = P; 
                P = P->lChild;
            }
        }
        else
        {
            if(S->top != -1)  //栈不空
            {
                P = S->data[ S->top--];  //出栈 
                printf("%c ",P->data);
                P = P->rChild;
            }
        }
    }
    printf("\n");
    return;
}


/*   普通二叉树 非递归 先序遍历  */
void PreOrder2(PBitTree T)
{
    printf("普通二叉树 非递归 先序遍历:\n");
    PBitTree P = T; //P是遍历指针
    PStack S = (PStack)malloc(sizeof(Stack));  S->top = -1; //初始化栈

    while( P || ( S->top != -1 ) )
    {
        if( P ) //遍历左孩子 
        {
            printf("%c ",P->data);
            S->data[++S->top] = P;  //入栈
            P = P->lChild;       
        } //出来是遇到了空 
        else
        {
            P = S->data[S->top--];  //出栈
            P = P->rChild;          
        }
    }
    printf("\n");
    return;
} 

/*   普通二叉树 非递归 后序遍历  */
void PostOrder2(PBitTree T)  
//重点在于判定指针是从左子树返回的还是右子树, 若右子树则该结点已经到顶了 
{
    printf("普通二叉树 非递归 后序遍历:\n");
    PBitTree P = T; //P是遍历指针

    PBitTree R = NULL; //辅助指针 

    PStack S = (PStack)malloc(sizeof(Stack));  S->top = -1; //初始化栈

    while( P || (S->top!=-1) )
    {
        if(P)   // 一直遍历到最左下面 
        {
            S->data[++S->top] = P;
            P = P->lChild; 
        }
        else 
        {
            P = S->data[S->top];    
            if(P->rChild != NULL && P->rChild!=R )  //如果右子树存在且未被访问过 
            {
                 P = P->rChild;
                 S->data[++S->top] = P;
                 P = P->lChild;
            }
            else
            {
                P = S->data[S->top--];
                printf("%c ",P->data);
                R = P;
                P = NULL;
            }
        }

    }
    printf("\n");
    return;
}

void PostOrder2_2(PBitTree T)  
{
    if(T == NULL)
    {
        return;
    }
    printf("通普二叉树 非递归 后序遍历\n"); 
    PBitTree P = T; 
    PStack S = (PStack)malloc(sizeof(Stack));
    S->top = -1;

    S->data[++S->top] = T;  //树根节点 双次入栈 
    S->data[++S->top] = T;
    while(S->top != -1)
    {
        P = S->data[S->top--];  
        if(S->top!=-1 && P==S->data[S->top])//栈不为空,且 曾经的栈 前两层相同 
        {
            //栈顶的左右孩子如果还有,则下次循环  曾经的栈 前两层相同 继续寻找最左边
            //结点的左右孩子,然后继续寻找直到找到左右孩子都没有了,就开始打印

            /*
                对于每个结点都压栈两次,在循环中,每次弹出的一个结点赋给P,如果P仍然等于
                栈的头结点,说明P的孩子们还有没被操作过的,应该把他的孩子们入栈,否则,访问P
                也就是说, 第一次弹出, 将P的孩子压栈, 第二次弹出, 访问P 
            */ 
            if(P->rChild != NULL)
            {
                S->data[++S->top] = P->rChild;
                S->data[++S->top] = P->rChild;
            }

            if(P->lChild != NULL)
            {
                S->data[++S->top] = P->lChild;
                S->data[++S->top] = P->lChild;
            }
        }
        else                                //曾经的栈 前两层不相同  
        {
            printf("%c ",P->data); 
        }
    }


    printf("\n");
    return; 
} 

/* 普通二叉树的遍历 从上到下,从左到右 */
void LevelOrder_from_H_to_L_L_to_R(PBitTree T)
{
    if(!T)return; //防止空树 
    printf("普通二叉树的遍历 从上到下,从左到右\n");
    PBitTree P = T; 
    PQueue Q = (PQueue)malloc(sizeof(Queue));  //新建队列 
    Q->front = Q->rear =0;

    Q->data[Q->rear] = P; Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE; //根结点入队
    while( Q->rear != Q->front )
    {
        P = Q->data[Q->front]; Q->front = (Q->front+1)%QUEUE_MAX_SIZE; //出队
        printf("%c ",P->data);
        //注意 如果需要层次遍历 从下到上,从右到左 可以在这里入栈,到最后在出栈

        if(P->lChild) 
        {
            Q->data[Q->rear] = P->lChild;  //入队 
            Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE; 
        } 

        if(P->rChild) 
        {
            Q->data[Q->rear] = P->rChild;
            Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE;
        }
    } 
    printf("\n");
    return; 
} 

猜你喜欢

转载自blog.csdn.net/qq_32460819/article/details/81735235