二叉树之线索二叉树 二叉树的中序线索化和线索化后的遍历 C++代码实验

/**
 * 中序线索化二叉树
 * 核心本质还是中序遍历,只不过在遍历时记录前驱后继的指针
 * 设定now和pre两个指针遍历,now为当前位置的结点,pre为刚刚经过的
 * 即now为pre的后继,pre为now的前驱
 * 则now的左空指针指向pre,pre的右空指针指向now
 */

#include<iostream>
using namespace std;

#define DataType int

typedef class ThreadTree{
    public:
    DataType data;
    ThreadTree *lchild,*rchild;     //左右指针
    int ltag,rtag;                  //标记左右指针指向前驱后继还是儿子结点
}ttNode,*tt;

/**
 * *********************************************************************************************************
 * 将之前bst构造的代码复制过来,先建立一棵树********************************************************************
 * *********************************************************************************************************
 */
#define test_length 12
DataType test_data[test_length]={5,3,1,4,9,2,4,2,7,6,8,9};     //测试用例
//BST插入数据
void Insert(tt &tt_now,DataType Insert_Data)  //注意由于操作的是指针,所以需要传引用过来,否则tt_now释放后原来的树不会有变化
{
    //树为空的话,新节点就作为根
    if(tt_now==nullptr)       
    {   //创建新节点
        ttNode *node;
        node = (ttNode*)malloc(sizeof(ttNode));
        node->data = Insert_Data;
        node->lchild = nullptr;
        node->rchild = nullptr;

        //对比于非线索化树,需要补充tag的初始化
        node->ltag = 0;
        node->rtag = 0;

        tt_now = node;
        cout<<"插入成功!插入数据:"<<Insert_Data<<endl;
    }
    //树不为空,就递归找子树,找到合适的位置
    else if(Insert_Data == tt_now->data)         //存在相同值的节点,插入失败       
    {
        cout<<"插入失败!插入数据: "<<Insert_Data<<" 已存在!"<<endl;
        return;
    }
    else if(Insert_Data > tt_now->data)          //比现在树根节点大,则向右边递归
    {
        Insert(tt_now->rchild,Insert_Data);
    }
    else                                         //比现在树根节点小,则向左边递归
    {
        Insert(tt_now->lchild,Insert_Data);
    }  
}
//这里的Create仅仅是一个批量的Insert,非必须
//只是注意如果不调用Create,tt需要手动初始化为nullptr
void Create_BST(tt &tt_now,DataType Create_Data[])
{
    tt_now = nullptr;
    for(int i=0;i<test_length;i++)
    {
        Insert(tt_now,Create_Data[i]);
    }
}
/**
 * *********************************************************************************************************
 * 中序线索化 ***********************************************************************************************
 * *********************************************************************************************************
 */
void InThread(tt &now,tt &pre)
{
    if(now!=nullptr)       //处理每一个结点,同时用于叶子节点的递归回归,叶子节点的子结点递归到这里时会直接返回
    { 
        //和中序遍历一样,先向左子结点递归,找到中序序列的头
        InThread(now->lchild,pre);         
        //然后就可以开始线索化,线索化的逻辑在最顶部已经说明,即考虑now的左空指针和pre的右空指针
        if(now->lchild == nullptr)      //左空指针存在
        {
            //则将左空指针指向前驱结点,即pre,同时标记tag
            now->lchild = pre;
            now->ltag = 1;
        }
        if(pre!=nullptr && pre->rchild == nullptr)     //前驱结点的右空指针存在
        {
            //将前驱结点的右空指针指向本结点,即它的后继,同时标记tag
            pre->rchild = now;
            pre->rtag = 1;
        }
        //本结点处理完成,别忘了更新pre
        pre = now;
        //继续标准化中序遍历的操作
        InThread(now->rchild,pre);
    }
}

/**
 * *********************************************************************************************************
 * 中序线索化的初始操作 *************************************************************************************
 * *********************************************************************************************************
 */
//上面的InThread()操作有两个遗留问题,一是pre的初始化,二是序列尾结点的后继没有处理,故在这里解决
void InThread_Init(tt T)
{
    tt pre = nullptr;     //序列头结点的前驱为空
    if(T!=nullptr)        //树不为空时进行线索化
    {
        InThread(T,pre);
        pre->rchild = nullptr;
        pre->rtag = 1;
    }
}

/**
 * *********************************************************************************************************
 * 中序线索化后的遍历 *************************************************************************************
 * *********************************************************************************************************
 */
void InThread_Traversal(tt T)
{
    //找到序列头结点,即树中最左下角的结点,它是最左分支的唯一ltag为1的结点
    tt tt_now = T;
    while(tt_now->ltag == 0)
    {
        tt_now = tt_now->lchild;
    }
    //开始遍历
    while(tt_now->rchild != nullptr)     //只有序列尾节点的右指针为空
    {
        cout<<tt_now->data<<" ";               //输出
        //寻找后继
        if(tt_now->rtag == 1)            //有tag,则右指针直接指向后继
        {
            tt_now = tt_now->rchild;
        }else                            //没有tag,则后继为其右子树中的序列头结点,即右子树中最左下结点
        {
            tt_now = tt_now->rchild;
            while(tt_now->ltag == 0)
            {
                tt_now = tt_now->lchild;
            }
        }
    }
    //最后依然尾节点要单独处理
    cout<<tt_now->data<<" "<<endl;
}

/**
 * *********************************************************************************************************
 * 测试 ****************************************************************************************************
 * *********************************************************************************************************
 */
int main()
{
    //构造二叉排序树
    tt t1;
    Create_BST(t1,test_data);
    Insert(t1,100);
    //中序线索化
    InThread_Init(t1);
    //遍历输出
    InThread_Traversal(t1);
}

运行结果:(利用线索遍历输出,BST的中序遍历结果即为递增序列)

插入成功!插入数据:5
插入成功!插入数据:3
插入成功!插入数据:1
插入成功!插入数据:4
插入成功!插入数据:9
插入成功!插入数据:2
插入失败!插入数据: 4 已存在!
插入失败!插入数据: 2 已存在!
插入成功!插入数据:7
插入成功!插入数据:6
插入成功!插入数据:8
插入失败!插入数据: 9 已存在!
插入成功!插入数据:100
1 2 3 4 5 6 7 8 9 100

附:二叉树之二叉排序树 插入和中序遍历 C++代码实验

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值