如何在 对称序线索二叉树 中找某结点 在先根序列中的 后继结点?

       我们知道,对称线索二叉树的意义在于,中序遍历这种二叉树时不需要栈结构,也不需要递归实现,而且可以确定某结点在中序序列中的前驱和后继结点。那么现在,如在利用对称序线索二叉树,找到某结点在先根序列中的后继结点呢?

       要找到先根序列中的后继结点,可以先直接先根周游已经构造好的对称序二叉树,得到这颗二叉树的先根序列,再搜索后继结点即可。那么,如何先根周游对称序二叉树?

       不妨以下面一颗对称序二叉树为例,


除了头结点外,根据对称序线索二叉树的特点,可以把二叉树的各个结点分为三类,左子树不是线索的、左子树是线索而右子树不是线索的、左右子树都是线索的(结点是线索说明该结点不存储信息)。因此,我们可以依照这三种类别对二叉树进行先根遍历:

 从二叉树的根结点开始,

1)当左子树不是线索时,顺着左子树一直向下,同时访问遍历到的结点

2)当左子树是线索而右子树不是线索时,访问右子树结点

3)当左、右子树都是线索时,借用线索,跨越父节点,直接访问父节点的右子树,直到右子树为空,先根遍历结束

算法实现如下,

void ThreadPreOrder(pThrTree t)                     //按先序遍历周游中序线索二叉树
{
    pThrTree p =t;
    if(t == NULL)   return;
    else    cout<<p->info;                          //先访问线索二叉树根结点

    while(p != NULL){
        if(p->llink != NULL && p->ltag == 0){       //左子树不是线索时,顺其一直向下
            p=p->llink;
            cout<<p->info;                          //访问
        }
        else if(p->rlink != NULL && p->rtag == 0){  //左子树是线索而右子树不是线索
            p=p->rlink;
            cout<<p->info;                          //访问
        }
        else if(p->rlink->rlink != NULL){           //左,右子树都是线索

                p=p->rlink->rlink;                  //顺线索越过根结点(已访问过)

                cout<<p->info;                      //访问
        }
        else                                        //先序遍历结束
            break;
    }
}

程序样例如下,首先根据特殊的先根序列构造普通的二叉树,然后对其进行对称序线索化,然后先根序列遍历对称序线索二叉树,得到先根序列,访问某结点的后继结点读者自己给出。输入样例以本文的二叉树为例,

#include <iostream>
#include <stack>
#include <cstring>
#include <cstdio>
#define MAXN 100
#define DataType char

using namespace std;

typedef struct ThrTreeNode* pThrTreeNode;
typedef struct ThrTreeNode* pThrTree;
struct ThrTreeNode{
    DataType info;
    pThrTreeNode llink,rlink;
    int ltag,rtag;
};

void Thread(pThrTree t)
{
    stack<pThrTree> s;
    pThrTree p = t, pre = NULL;
    if(t == NULL)   return;
    do{
        while(p){                   //遇到结点压入栈,然后进入其左子树
            s.push(p);  p=p->llink;
        }
        p=s.top();  s.pop();
        if(pre){
            if(pre->rlink == NULL){ //修改前驱结点的右指针
                pre->rlink = p;
                pre->rtag = 1;
            }
            if(p->llink == NULL){   //修改该节点的左指针
                p->llink = pre;
                p->ltag = 1;
            }
        }
        pre = p; p=p->rlink;
    }while(!s.empty() || p);
}

void ThreadPreOrder(pThrTree t)                     //按先序遍历周游中序线索二叉树
{
    pThrTree p =t;
    if(t == NULL)   return;
    else    cout<<p->info;                          //先访问线索二叉树根结点

    while(p != NULL){
        if(p->llink != NULL && p->ltag == 0){       //左子树不是线索时,顺其一直向下
            p=p->llink;
            cout<<p->info;                          //访问
        }
        else if(p->rlink != NULL && p->rtag == 0){  //左子树是线索而右子树不是线索
            p=p->rlink;
            cout<<p->info;                          //访问
        }
        else if(p->rlink->rlink != NULL){           //左,右子树都是线索

                p=p->rlink->rlink;                  //顺线索越过根结点(已访问过)

                cout<<p->info;                      //访问
        }
        else                                        //先序遍历结束
            break;
    }
}

pThrTree CreateBinTree(char seq[],int &i,int k){
                                    //创建普通二叉树
   if(i>k||seq[i]=='#')
       return NULL;
   pThrTreeNode p=new struct ThrTreeNode;
   if(p!=NULL){
       p->info=seq[i];
       p->ltag=p->rtag=0;           //初始化标志量
       i++;
       p->llink=CreateBinTree(seq,i,k);
       i++;
       p->rlink=CreateBinTree(seq,i,k);
       return p;
    }
    return NULL;
}
int main()
{
    char seq[MAXN];
    scanf("%s",seq);
    int k=0;
    pThrTree t = CreateBinTree(seq, k, strlen(seq)-1);
    Thread(t);
    ThreadPreOrder(t);
    return 0;
}

INPUT:

ABC##D##EF#GH##I###
OUTPUT:
ABCDEFGHI
另外,中序遍历对称序线索二叉树和构造二叉树的算法见于 http://blog.csdn.net/gnosed/article/details/79542228 。

猜你喜欢

转载自blog.csdn.net/gnosed/article/details/79608842
今日推荐