二叉树的建立以及遍历C/C++

一、 二叉树的定义
二叉树(Binary Tree)是个有限元素的集合,该集合或者为空,或者由一个称为根(root)的元素及两个不相交的、分别被称为左子树和右子树的二叉树组成。当集合为空时,称该二叉树为空二叉树,在二叉树中,一个元素也成为一个节点。
这里写图片描述
二、 二叉树的数据结构
下面为二叉树链式存储结构的定义:

 /*
 *定义二叉树的数据结构
 */
typedef char datatype ;
typedef struct BiTNode
{
    datatype data ; //数据域
    struct BiTNode *lchild , *rchild ; //孩子的左右节点
} BiTNode , *BiTree ;

三、 二叉树的递归遍历
1、 二叉树的前序遍历
若二叉树为非空,则依次进行如下操作:
(1) 访问根节点;
(2) 先序遍历左子树;
(3) 先序遍历右子树;
算法如下:

/*
 *进行二叉树的先序遍历
 */
void PreOrder(BiTree bt)
{
    if(bt == NULL) //递归的结束的条件
    {
        return ;
    }
    printf("%c " , bt->data) ;
    PreOrder(bt->lchild) ;
    PreOrder(bt->rchild) ;
}

2、 二叉树的中序遍历
若二叉树为非空,则依次进行如下操作:
(1)中序遍历左子树;
(2)访问根节点;
(3)中序遍历右子树;
算法如下:

/*
 *中序遍历二叉树
 */
void InOrder(BiTree bt)
{
    if(bt == NULL) //递归的结束条件
    {
        return ;
    }
    InOrder(bt->lchild) ;
    printf("%c " , bt->data) ;
    InOrder(bt->rchild) ;
}

3、 二叉树的后续遍历
若二叉树为非空,则依次进行如下操作:
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根节点;
算法如下:

/*
 *后序遍历二叉树
 */
void PostOrder(BiTree bt)
{
    if(bt == NULL) //递归的结束条件
    {
        return ;
    }
    PostOrder(bt->lchild) ;
    PostOrder(bt->rchild) ;
    printf("%c " , bt->data) ;
}

4、 二叉树的层次遍历
借助队列的数据结构进行层次遍历
(1) 访问当前队头节点;
(2) 若该元素所指节点的左、右孩子节点非空,则将该元素所指节点的左孩子指针和右孩子指针顺序入队;
(3) 此过程不断进行,当队列为空时,二叉树的层次遍历结束;
算法如下:

/*
 *用队列实现二叉树的层次遍历
 */
 void LevelOrder(BiTree bt)
 {
     BiTree quene[MAXSIZE] ;
     int front , rear ; //分别指向队列的队首语队尾
     if(bt == NULL)
     {
         return ;
     }
     front = -1 ;
     rear = 0 ;
     quene[rear] = bt ;
     while(front != rear)
     {
         front++ ;
         printf("%c " , quene[front]->data) ;
         if(quene[front]->lchild != NULL) //将队首的左孩子节点加入队列
         {
             rear++;
             quene[rear] = quene[front]->lchild ;
         }
         if(quene[front]->rchild != NULL) //将队首的右孩子节点加入队列
         {
             rear++;
             quene[rear] = quene[front]->rchild ;
         }
     }
 }

四、 二叉树的非递归遍历
1、 二叉树的非递归前序遍历
借助栈存储当前访问的节点,栈为空时,访问结束。
算法如下:

/*
  *进行二叉树的非递归前序遍历
  */
void  NRPreOrder(BiTree bt)
{
    BiTree stack[MAXSIZE] , p ;
    int i , top ;
    if(bt == NULL)
    {
        printf("二叉树为空!\n") ;
        return ;
    }
    top = 0 ;
    p = bt ;
    while(p != NULL || top != 0)
    {
        while(p != NULL)
        {
            printf("%c " , p->data) ; //范围访问当前元素
            if(top < MAXSIZE - 1)
            {
                stack[top] = p ; //将当前结点压栈
                top++ ;
            }
            else
            {
                printf("栈溢出!\n") ;
                return ;
            }
            p = p->lchild ; //指针指向该节点的左孩子
        }
        if(top <= 0)
        {
            return ;
        }
        else
        {
            top-- ;
            p = stack[top] ; //从栈中弹出栈顶元素
            p = p->rchild ; //指针指向该节点的右孩子
        }
    }
}

2、 二叉树的非递归中序遍历
只需将访问节点的代码移动到p = stack[top] 和 p = p->rchild 之间即可。
算法如下:

/*
 *进行非递归的中序遍历
 */
void NRInOrder(BiTree bt)
{
   BiTree stack[MAXSIZE] , p ;
    int i , top ;
    if(bt == NULL)
    {
        printf("二叉树为空!\n") ;
        return ;
    }
    top = 0 ;
    p = bt ;
    while(p != NULL || top != 0)
    {
        while(p != NULL)
        {
            if(top < MAXSIZE - 1)
            {
                stack[top] = p ;
                top++ ;
            }
            else
            {
                printf("栈溢出!\n") ;
                return ;
            }
            p = p->lchild ;
        }
        if(top <= 0)
        {
            return ;
        }
        else
        {
            top-- ;
            p = stack[top] ;
            printf("%c " , p->data) ; //范围访问当前元素
            p = p->rchild ;
        }
    }
}

3、 二叉树的后序遍历
在后序遍历过程中,节点在第一次出栈后,还需再次入栈,也就是说节点要入两次栈,出两次栈。而访问节点是在第二次出栈是进行的。因此为了区别节点出栈的次数,定义数据结构:

/*
 *为二叉树的后续遍历建立数据结构
 */
typedef struct
{
    BiTree bt ;
    int flag ;
} stacktype ;
算法如下:
/*
 *进行二叉树的后序遍历
 */
void NRPostOrder(BiTree bt)
{
    stacktype stack[MAXSIZE] ;
    int top , sign ;
    BiTree p ;
    if(bt == NULL)
    {
        return ;
    }
    top = -1 ;
    p = bt ;
    while(p != NULL || top != -1)
    {
        if(p != NULL)
        {
            top++ ;
            stack[top].bt = p ;
            stack[top].flag = 1;
            p = p->lchild ;
        }
        else
        {
            p = stack[top].bt ;
            sign = stack[top].flag ;
            top-- ;
            if(sign == 1)
            {
                //进行二次压栈
                top++ ;
                stack[top].bt = p ;
                stack[top].flag = 2 ;
                p = p->rchild ;
            }
            else
            {
                printf("%c " , p->data) ; //进行二叉树的访问
                p = NULL ;
            }
        }
    }
}

五、 二叉树的建立
由二叉树的性质可知,二叉树可有先序序列和中序序列唯一确定,而后序序列与中序序列无法确定唯一二叉树。
算法思想是:运用递归求解二叉树,先根据先序序列的第一个元素建立根节点;然后在中序序列中找到该元素,确定根节点的左、右子树的中序序列;再在先序序列中确定左、右子树的先序序列;最后由左子树的先序序列与中序序列建立左子树,由右子树的先序序列与中序序列建立右子树。
算法如下:

void PreInO(char preOrder[] , char inOrder[] , int i , int j , int k , int h , BiTree *bt)
{
    int m ;
    if(!((*bt) = (BiTree)malloc(sizeof(BiTNode))))
    {
        return ;
    }
    else
    {
       (*bt)->data = preOrder[i] ;
        m = k ;
        while(preOrder[i] != inOrder[m])
        {
            m++ ;
        }
        if(m == k)
        {
            (*bt)->lchild = NULL ;
        }
        else
        {
            PreInO(preOrder , inOrder , i + 1 , m - k + i , k , m - 1 , &((*bt)->lchild)) ; //进行左子树的建立
        }
        if(m == h)
        {
            (*bt)->rchild = NULL ;
        }
        else
        {
            PreInO(preOrder , inOrder , m - k + i + 1 , j , m + 1 , h , &((*bt)->rchild)) ; //进行右子树的建立
        }
    }
}
/*
 *根据二叉树的前序遍历序列和中序遍历确定唯一二叉树
 *根据二叉树的中序遍历和后续遍历不能确定唯一二叉树
 */
void ReBiTree(char preOrder[] , char inOrder[] , BiTree *bt)
{
    int len ;
    len = strlen(preOrder) ;
    if(len <= 0)
    {
        return ;
    }
    else
    {
        PreInO(preOrder , inOrder , 0 , len - 1 , 0 , len - 1 , bt) ;
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值