线索化二叉树的创建及遍历

本文详细介绍了如何创建线索二叉树,并探讨了其遍历的算法过程,通过具体的测试代码进行实例解析。
摘要由CSDN通过智能技术生成
#include<stdio.h>
#include<iostream>
using namespace std;

enum thread
{
    LINK,
    THREAD,
};
template<class T>
struct BinaryTreeThdNode
{
    BinaryTreeThdNode()
        :_pLeft(NULL)
        ,_pRight(NULL)
        ,_pParent(NULL)
        ,_leftThread(LINK)
        ,_rightThread(LINK)
    {}

    T _data;
    BinaryTreeThdNode* _pLeft;//左孩子
    BinaryTreeThdNode* _pRight;//右孩子
    BinaryTreeThdNode* _pParent;//双亲节点
    enum thread _leftThread;//左索引
    enum thread _rightThread;//右索引
};

template<class T>
class BinaryTreeThd
{
public:
    typedef BinaryTreeThdNode<T> Node;

    BinaryTreeThd()//线索二叉树的构造
        :_pRoot(NULL)
    {}
    BinaryTreeThd(const T array[],size_t size,T invalid)//线索二叉树的构造
    {
        size_t index=0;
        _pRoot = _CreateTree(_pRoot,array,size,index,invalid);//二叉树的创建
    }

    void PreThreading()//前序线索化
    {
        Node* prev = NULL;
        _PreThreading(_pRoot,prev);
    }

    void InThreading()//中序线索化
    {
        Node* prev = NULL;
        _InThreading(_pRoot,prev);
    }

    void PostThreading()//后序线索化
    {
        Node* prev = NULL;
        _PostThreading(_pRoot,prev);
    }

    void PreOrder()
    {
        // 找最左边的节点并访问路径上的节点---访问该最左节点---判断右子树是否为NULL,若为NULL,访问连续后继节点
        //若不为NULL,则pCur=pCur->_pRight将右子树重新作为一棵树进行访问
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        while(pCur)
        {
            while(pCur->_leftThread == LINK)
            {
                cout<<pCur->_data<<" ";
                pCur = pCur->_pLeft;
            }
            cout<<pCur->_data<<" ";
            //while(pCur->_rightThread == THREAD)// 判断该节点的右子树不存在,访问后继节点
            //{
            //  pCur = pCur->_pRight;
            //  cout<<pCur->_data<<" ";
            //}
            //if(pCur->_leftThread == LINK)//再访问完后继结点后,可能有两种情况,存在左子树,则先访问左子树,当作新树来处理
            //{
            //  pCur = pCur->_pLeft;
            //}
            //if(pCur->_rightThread == LINK)//再访问完后继节点,可能没有左子树,只有右子树,或则最左节点右子树存在,则当作新树处理
            //{
            //  pCur = pCur->_pRight;
            //}

            //代码优化---将上面注释起来的代码用下面一句代码替换
            pCur = pCur->_pRight;//全部当作新的树来处理
        }
    }

    void InOrder()//中序线索化二叉树的中序遍历
    {
        // 找到最左端的节点,不访问路径,找到之后访问最左端的节点---再判断其有无右子树,若有,作为新树去处理,若没有,连续访问其后继节点
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        while(pCur)
        {
            while(pCur->_leftThread == LINK)
            {
                pCur = pCur->_pLeft;
            }
            cout<<pCur->_data<<" ";
            while(pCur->_rightThread == THREAD)
            {
                pCur = pCur->_pRight;
                cout<<pCur->_data<<" ";
            }
            pCur = pCur->_pRight;
        }
    }

    void PostOrder()//后序线索化二叉树的后序遍历
    {
        //找到最左节点,不访问,首先判断该节点的右子树是否存在,若不存在,访问该节点并到其后继节点,若存在,则访问右子树
        //单纯的这样写,会导致死循环问题,在3的地方,原因是6已经访问过了,但pCur=pCur->_pRight还是指向6,接着访问6和3,死循环---解决办法prev标记访问过的
        //仅仅是标记过了还是有问题,1没有办法访问到---解决办法,设立双亲节点
        //特殊的索引树--左单枝问题,根节点没有访问(最后一个节点的右索引是LINK)---解决办法,if判断
        //左单支问题
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        Node* prev = NULL;//标记访问过的节点

        while(pCur)
        {
            while(pCur->_leftThread == LINK && pCur->_pRight != prev)
                pCur = pCur->_pLeft;
            while(pCur->_rightThread == THREAD)
            {
                cout<<pCur->_data<<" ";
                prev = pCur;
                pCur = pCur->_pRight;
            }
            if(pCur==_pRoot && pCur->_pRight==NULL)
            {
                cout<<pCur->_data<<" ";
                return ;
            }
            while(pCur && pCur->_pRight==prev)
            {
                cout<<pCur->_data<<" ";
                prev = pCur;
                pCur = pCur->_pParent;
            }
            if(pCur && pCur->_pRight != prev)
            pCur = pCur->_pRight;
        }
    }
private:

    //底层实现

    Node* _CreateTree(Node* pRoot,const T array[],size_t size,size_t& index,T& invalid)//二叉树的创建
    {
        if(index<size && array[index]!=invalid)
        {
            pRoot = new Node;
            pRoot->_data = array[index];
            pRoot->_pLeft = _CreateTree(pRoot->_pLeft,array,size,++index,invalid);
            if(pRoot->_pLeft)
                pRoot->_pLeft->_pParent = pRoot;
            pRoot->_pRight = _CreateTree(pRoot->_pRight,array,size,++index,invalid);
            if(pRoot->_pRight)
                pRoot->_pRight->_pParent = pRoot;
        }
        return pRoot;
    }
    void _PreThreading(Node* pRoot,Node*& prev)//前序线索化---采用先线索化根节点,判断根节点左右子树是否存在,再利用递归线索化左子树和右子树的的节点
    {
        if(pRoot)
        {
            if(pRoot->_pLeft == NULL)// 线索化当前指针的左指针域
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }

            if(prev!=NULL && prev->_pRight==NULL)//线索化前一个节点的右指针域
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }

            prev=pRoot;
            if(pRoot->_leftThread != THREAD)//防止索引后陷入死循环
            _PreThreading(pRoot->_pLeft,prev);
            if(pRoot->_rightThread != THREAD)
            _PreThreading(pRoot->_pRight,prev);
        }
    }

    void _InThreading(Node* pRoot,Node*& prev)//中序线索化
    {
        if(pRoot)
        {
            _InThreading(pRoot->_pLeft,prev);//找到最左边的节点

            if(pRoot->_pLeft==NULL)//线索化该节点的左指针域
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }
            if(prev && prev->_pRight==NULL)//线索化前一个节点的右指针域
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }
            prev = pRoot;//该节点的左指针域线索完毕,标记该节点,
            if(pRoot->_rightThread != THREAD)
                _InThreading(pRoot->_pRight,prev);//线索化右子树的节点
        }
    }

    void _PostThreading(Node* pRoot,Node*& prev)//测试二叉树的后续索引
    {
        if(pRoot)
        {
            _PostThreading(pRoot->_pLeft,prev);
            _PostThreading(pRoot->_pRight,prev);

            if(pRoot->_pLeft == NULL)
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }
            if(prev && prev->_pRight==NULL)
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }
            prev = pRoot;
        }
    }
private:
    Node* _pRoot;
};

测试代码

void funtest()
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//测试线索二叉树的创建
    //t1.PreThreading();//测试线索二叉树的先序索引
    //t1.InThreading();//测试线索二叉树的中序索引
    //t1.PostThreading();//测试线索二叉树的后序线索
}

void funtest1()//测试前序索引二叉树的前序遍历
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);
    t1.PreThreading();
    t1.PreOrder();
}

void funtest2()//测试中序索引二叉树的中序遍历
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//测试线索二叉树的创建
    t1.InThreading();
    t1.InOrder();
}

void funtest3()//测试后序索引二叉树的后序遍历
{
    //char str[] = {"124###35##6"};
    char str[] = {"12#3##45#6#7##8"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//测试线索二叉树的创建
    t1.PostThreading();
    t1.PostOrder();
}

int main()
{
    //funtest();
    //funtest1();
    //funtest2();
    funtest3();
    getchar();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值