数据结构P4.3:二叉树的遍历


什么是遍历

  • 照某种次序把所有结点都访问一边
  • 线性结构中:对于链表、队列都有从前往后或者从后往前的依次遍历
  • 的结构中:基于树的层次特性确定的次序规则可以是层次遍历
  • 树的先序遍历:按照 根节点->左节点->右节点 顺序依次遍历
  • 树的中序遍历:按照 左节点->根节点->右节点 顺序依次遍历
  • 树的后序遍历:按照 左节点->右节点->根节点 顺序依次遍历

二叉树的先序遍历

  • 遍历顺序:先访问根结点,再访问左右结点
  • 算法思想:利用递归,访问每层的根结点、左结点、右结点
//二叉树的先序遍历代码伪代码
1.从整棵树BiTree的根结点T开始访问T的左结点、右节点
2.如果左节点有子结点,把左结点当作所在层的根结点,循环上述步骤直至左右结点为空
3.右结点一样的方式
  • 算法步骤
1.若二叉树为空,则无需操作
2.若二叉树非空
	1.访问根结点
	2.先序遍历左子树
	3.先序遍历右子树
  • 图解
    在这里插入图片描述

代码实现

//二叉树的先序遍历代码
//二叉树的结点(链式存储)
typedef struct BiTNode{
    char data;
    struct BiTNode *lchild, *rchild;    /*左右子结点*/
}BiTNode,*BiTree;

//先序遍历
void PreOrder(BiTree T){
    if(T!=NULL){
        visit(T)                /*访问根节点*/
        PreOrder(T->lchild);    /*递归遍历左子树,结束条件为遇到空结点*/
        PreOrder(T->rchild);    /*递归遍历右子树,开始条件递归遍历左子树,结束条件为遇到空结点*/
    }
}

二叉树的中序遍历

  • 遍历顺序:先访问左结点,再访问根结点、右结点
  • 算法思想:利用递归,访问每层的左结点、根结点、右结点
//二叉树的先序遍历代码伪代码
1.从整棵树BiTree的根结点T的左结点开始访问根结点、右结点
2.如果左节点有子结点,把左结点当作所在层的根结点,循环上述步骤直至左右结点为空
3.右结点一样的方式
  • 算法步骤
1.若二叉树为空,则无需操作
2.若二叉树非空
	1.先序遍历左子树
	2.访问根节点
	3.先序遍历右子树
  • 图解
    在这里插入图片描述

代码实现

//二叉树的中序遍历代码
void InOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);    /*递归遍历左子树,结束条件为遇到空结点*/
        visit(T)                /*访问根节点*/
        InOrder(T->rchild);    /*递归遍历右子树,开始条件递归遍历左子树,结束条件为遇到空结点*/
    }
}

二叉树的后序遍历

  • 遍历顺序:先访问左右结点,最后访问根结点
  • 算法思想:利用递归,访问每层的左结点、右结点、根结点
//二叉树的先序遍历代码伪代码
1.从整棵树BiTree的根结点T的右结点开始访问左结点、根结点
2.如果左结点有子结点,把左结点当作所在层的根结点,循环上述步骤直至左右结点为空
3.右结点一样的方式
  • 算法步骤
1.若二叉树为空,则无需操作
2.若二叉树非空
	1.先序遍历左子树
	2.先序遍历右子树
	3.访问根节点
  • 图解
    在这里插入图片描述

代码实现

//二叉树的后序遍历代码
void PostOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);    /*递归遍历左子树,结束条件为遇到空结点*/
        InOrder(T->rchild);    /*递归遍历右子树,开始条件递归遍历左子树,结束条件为遇到空结点*/
        visit(T)                /*访问根节点*/
    }
}

二叉树的层序遍历

  • 下面这样的一棵树,应该怎么样实现它的遍历?
    在这里插入图片描述

  • 需要从第一层的 根结点开始一层层的进行遍历,按照访问上层父节点的子结点这样的规则逐层遍历

算法思想

  1. 借助辅助队列来存放要访问的结点,初始化这个辅助队列
  2. 根结点先入队
  3. 循环条件:若队列为非空,则队头结点出队(FIFO),访问的就是该父结点,然后将其左、右子节点插入队尾后续访问(如果存在)
  4. 重复步骤3直至队列为空
  • 图解
    在这里插入图片描述

代码实现

//链式队列结点定义
typedef struct LinkNode{        /*链式队列的结点*/
    BiTNode *data;              /*数据域,类型为树的结点指针,而不是结点,节省空间*/
    struct LinkNode *next;      /*指向下一个结点的指针*/
}LinkNode;

typedef struct{                 /*链式队列的定义*/
    LinkNode *head,*tail;       /*队列的队头和队尾指针*/
}LinkQueue;

//带头结点的链式队列初始化
bool InitLinkQueue(&Q){
    LinkNode *L=(LinkNode*)malloc(sizeof(LinkNode));     /*声明一个头结点指针L并分配空间*/
    Q.head=Q.tail=L;                                    /*初始化时,队头,队尾都指向头结点*/
}

//判断是否空队列(带头结点)
bool IsEmptyQueue(Q){
    if(Q.tail==Q.head)
        return true;            /*队空*/
    else
        return false;           /*队非空*/
}


//插入,新元素入队(带头结点)
void EnLinkQueue(LinkQueue &Q,ElemType x){
    LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));     /*声明一个新结点指针s并分配空间*/
    s->data=x;                                            /*将要插入的元素赋值给新节点的数据域*/
    s->next=NULL;                                         /*新结点s是要插入到队尾的,因此指向NULL*/    
    Q.tail->next=s;                                       /*新的结点插入到当前队列的Q的队尾,相当于当前Q的队尾指针的下一个结点是s*/
    Q.tail=s;                                             /*修改队尾指针,结点s为Q的新队尾*/
}

//删除,队头元素出队(带头结点)
bool DeLinkQueue(LinkQueue &Q,ElemType &x){
    if(Q.tail==Q.head)                      /*带头结点空队判断条件*/
        return false;
    LinkNode *p=Q.head->next                /*删除的结点p是当前队列的头结点的下一个结点(当前队头head=Q.head->next)*/
    x=p->data;                              /*变量x返回当前结点p(当前队头)数据*/
    Q.head->next=p->next;                   /*修改当前Q的队头head指针为p结点的下一个结点*/
    //等价于:Q.head->next=Q.head->next->next;
    if(p==Q.tail)                           /*删除的结点p如果是队尾*/
        Q.tail=Q.head;                      /*修改tail指针*/
    free(p);                                /*释放结点p*/
    return true;
}


//层序遍历
void LevelOrder(BiTree T){
    LinkQueue Q;                /*声明一个辅助队列Q*/    
    InitLinkQueue(Q);           /*初始化辅助队列Q*/                            
    BiTree p;
    EnLinkQueue(Q,T);           /*根结点入队*/
    while(!IsEmptyQueue(Q)){    /*只要队列不为空就循环*/
        DeLinkQueue(Q,p)        /*队头结点出队*/
        visit(p)/*访问出队的结点,打印结点的值等等*/
        if(p->lchild!=NULL)
            EnLinkQueue(Q,p->lchild);  /*出队结点的左孩子入队*/
        if(p->rchild!=NULL)
            EnLinkQueue(Q,p->rchild);  /*出队结点的右孩子入队*/
    }     
}

由遍历序列构造二叉树

  • 一种遍历序列会对应多种二叉树形态
  • 由于 中序+任意序列即可确定一颗二叉树的形态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kxwang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值