二叉树的遍历

二叉树的遍历

一、先序遍历NLR

//递归算法
void PreOrder(BiTree T){
     if(T!=NULL){
         visit(T);//访问根节点
         PreOrder(T->lchild);
         PreOrder(T->rchild);
     }
}
//非递归算法
void PreOrder(BiTree T){
    InitStack(S);//初始化栈
    BiTree p=T;
    while(p||!IsEmty(S)){
        if(P){//一路向左
            visit(p);
            Push(S,p);//访问并入栈
            p=p->lchild; //左孩子不为空一直往左走
        }
        else{//出栈并访问该元素的右子树
            Pop(S,p);//出栈
            p=p->rchild;//向右子树走
        }
    }
}

二、中序遍历LNR

//递归实现
void InOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}
//非递归实现
void InOrder(BiTree T){
    InitStack(S);BiTree p=T;
    while(p||!IsEmpty(S)){
        if(p){//一路向左
            Push(S,p);//当前结点入栈 
            p=p->lchild;//左孩子不为空,一直向左走
        }
        else{//出栈,走右子树
            Pop(S,p);visit(p);//访问栈顶结点
            p=p->rchild;
        }
    }
}
//非递归实现的原理:1.沿着根的左孩子,依次入栈直到左孩子为空。说明已将找到可以输出的结点。2.栈顶元素出栈并访问:若右孩子为空,继续执行2;若其右孩子不为空,将右子树转执行1.

三、后序遍历 LRN

//递归实现
void PostOrder(BiTree){
    if(T!=NULL){
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T);
    }
}
//非递归实现算法思想:1.沿着根的左孩子,依次入栈,直到左孩子为空。2。读栈顶元素:若其右孩子不为空且未被访问,将右子树转执行1;否则栈顶元素出栈并访问。
void PostOrder(BiTree){
    InitStack(S);
    p=T;
    r=NULL;//r标志刚才被访问的结点
    while(p||!IsEmpty(S)){
        if(p){
            Push(S,p);
            p=p->lchild;
        }
        else{
            GetTop(S,p);//向右
            if(p->rchild&&p-rchild!=r)//若右子树存在且未被访问过
                p=p->rchild;
            else{//否则弹出结点并访问
                pop(S,p);
                visit(p->data);
                r=p;//标记最近访问过的结点
                p=NULL;//访问完毕,p置空
            }
        }
    }
}
//注意每次出栈访问完一个结点就相当于遍历完以该结点为根的子树,需将P置NULL

四、层次遍历

层次遍历需要借助一个队列。先将根节点入队,然后出队访问该结点,若它有左子树则左子树的根节点入队;若其有右子树将右子树的根节点入队。。。。

void LevelOrdr(BiTree T){
    InitQueue(Q);
    BiTree p;
    EnQueue(Q,T);//将根节点入队
    while(!IsEmpty(Q)){
        DeQueue(Q,p);//头结点出队
        visit(p);
        if(p->lchild!=NULL)
            EnQueue(Q,p->lchild);
        if(p->rchild!=NULL)
            EnQueue(Q,p->rchild);//右子树不空,右子树的根节点入队
    }
}

五、由遍历构造二叉树

由中序序列和后序序列或者先序序列可以唯一的确定一棵二叉树。

由二叉树的层序遍历和中序遍历也可以唯一确定一棵二叉树。

线索二叉树

因为二叉树的遍历可以唯一的得到一个遍历序列,基于那种遍历方法的顺序序列,每个结点都有一个直接的前驱和后继。传统的二叉链表存储只能体现父子关系,不能直接得到结点在遍历中的前驱和后继。n个结点的二叉树中有n+1个空指针。可以从这些空指针来指向遍历中的前驱和后继。因此在结点上增加两个标志域:ltag和rtag。值为0则表示lchild指针指向的是结点的左孩子。值为1则表示lchild指针指向节点的前驱(右为后继)

//存储结构描述如下
typedef struct ThreadNode{
    ElemType data;
    struct ThreadNode *lchild,*rchild;
    int ltag,rtag;
}ThreadNode,*ThreadThree;

一、中序二叉线索树

线索化实质就是遍历一遍二叉树,从遍历中得知结点的前驱后继信息。

//pre是刚刚访问过的结点,p是正在访问的结点
void InThread(ThreadTree &p,ThreadTree &pre){
   if(p){
       InThread(p->lchild,pre);//递归线索化左子树
       if(p->lchild==NULL){//左子树为空建立线索
           p->lchild=pre;
           p->ltag=1;
       }  
       if(pre!=NULL&&pre->rchild==NULL){
           pre->rchild=p;//建立前驱结点的后继线索
           pre->rtag=1;
       }
       pre=p;
       InThread(p->rchild,pre);//递归,线索化右子树
   }
}
//建立线索二叉树
void CreateThread(ThreadTree T){
    ThreadTree pre=NULL;
    if(T!=NULL){
        InThread(T,pre);//线索化二叉树
        if(pre->rchild==NULL){
          pre->rchild=NULL;//处理遍历的最后一个结点
          pre->rtag=1;
        }
    }
}
//中序线索二叉树的遍历
//1.求中序线索二叉树序列下的第一个结点
ThreadNode *Firstnode(ThreadNode *p){
    while(p->ltag==0)p=p->lchild;
    return p;
}
//2.求中序线索二叉树中的结点p在中序序列下的后继
//若其右标志位1,则右边位线索指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点为其后继)
ThreadNode *NextNode(ThreadNode *p){
    if(p->rtag==0)return FirstNode(p->rchild);
    else return p->rchild;
}
//3.中序线索二叉树最后一个结点
ThreadNode *lastnode(ThreadNode *p){
    while(p->rtag==0)p=p->rchild;
    return p;
}
//4.求p结点的前驱
ThreadNode *preNode(ThreadNode *p){
    if(p->ltag==0)return lastnode(p->lchild);
    else return p->lchild;
}
//5.中序线索二叉树的中序遍历算法
void Inoder(ThreadNode *T){
    for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
        visit(p);
}

二、先序线索二叉树

线序线索二叉树的构造,只需变动线索构造代码段中与左右子树递归函数的位置即可。通过二叉树应该掌握线索化二叉树的构造。一般的方法是,由先序序列和二叉树,标记连接即可。

三、后序线索二叉树

后序线索二叉树的建立,只需要改变顺序为LRN(即线索化放置在最后即可)

其中后序线索二叉树中找节点的后继较为复杂,可分为三种情况:1、若结点x是二叉树的根,则其后继为空。2.若节点x是其双亲结点的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲;3.若结点x是双亲的左孩子,且其双亲有右子树,则其后继为其右子树上后序遍历列出的第一个结点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值