/**
* 中序线索化二叉树
* 核心本质还是中序遍历,只不过在遍历时记录前驱后继的指针
* 设定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