目录
前言
线索二叉树以及线索化的概念,节点改造请见博客:线索二叉树剖析【C/C++】
本文将介绍先序线索化二叉树的算法思路以及代码实现
温故知新
线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继的信息只有在遍历该二叉树时才能得到,所以线索化的过程就是在遍历的过程中修改空指针的过程。
也就是说,我们只对含孩子指针为空的节点进行改造
先序线索化思路
1、算法整体结构仍是一个先序遍历,只不过遍历过程中对空指针进行改造
2、空指针改造无非指向前驱或者后继,所以我们需要一个指向前驱节点的指针prev
3、对于待改造节点,如果左孩子为空,那么我们需要把它指向当前节点的前驱节点,并且标记左孩子为线索节点
4、对于待改造节点,如果右孩子为空,那么我们需要把它指向当前节点的前驱节点,并且标记右孩子为线索节点
5、当前节点改造完毕,我们需要依次改造仍为非线索节点的左子树右子树
代码实现
先序线索化代码
有没有发现无论是中序线索化还是先序线索化都是在中序/先序遍历中加入了相同的操作
void PrevThreading(BiThrNode *root, BiThrNode *&prev) // 主程序调用该函数时prev为nullptr
{
if (!root)
return;
if (!root->_left)
{
// 当前节点左为空,则当前节点左指向前驱也就是prev
root->_left = prev;
root->_ltag = PointerTag::Thread;
}
if (prev != nullptr && !(prev->_right))
// 前驱节点右为空,则前驱节点指向后继也就是root
// 前驱节点的左已经在前驱节点的线索化函数内处理过了
{
prev->_right = root;
prev->_rtag = PointerTag::Thread;
}
prev = root;
if (root->_ltag == PointerTag::Link)
PrevThreading(root->_left, prev); // 递归线索化左子树
if (root->_rtag == PointerTag::Link)
PrevThreading(root->_right, prev); // 递归线索化右子树
}
先序线索二叉树遍历
遍历思路
先序线索二叉树遍历是三种线索二叉树中最简单的一种
如果左节点为link节点,那么我们就一直往左遍历即可
当遍历到左节点为Thread节点,我们就往右一直遍历
先序线索二叉树遍历代码
void PrevOrderTraverse_Thr(BiThrNode *root)
{
if (!root)
return;
while (root)
{
// 当_ltag为Link就遍历左子树
while (root->_left && root->_ltag == PointerTag::Link)
{
cout << root->_data << " ";
root = root->_left;
}
cout << root->_data << " ";
if (root->_ltag == PointerTag::Thread) // 遇到线索,看右节点
root = root->_right;
while (root)
{
// 当_ltag为Link就退出遍历左子树
if (root->_ltag == PointerTag::Link && root->_left)
break;
cout << root->_data << " ";
root = root->_right;
}
}
}
示例程序
仍以该二叉树为例
主函数代码
int main()
{
// 构建示例图二叉树
BiThrNode *_root = new BiThrNode('A');
_root->_left = new BiThrNode('B');
_root->_right = new BiThrNode('C');
_root->_left->_left = new BiThrNode('D');
_root->_left->_right = new BiThrNode('E');
_root->_right->_left = new BiThrNode('F');
_root->_right->_right = new BiThrNode('G');
_root->_left->_left->_left = new BiThrNode('H');
_root->_left->_left->_right = new BiThrNode('I');
_root->_left->_right->_left = new BiThrNode('J');
// 线索化前的先序遍历
cout << "线索化前的先序遍历"
<< ": ";
PrevOrder(_root);
// 线索化后的先序遍历
BiThrNode *prev = nullptr;
PrevThreading(_root, prev);
cout << "线索化后的先序遍历"
<< ": ";
PrevOrderTraverse_Thr(_root);
return 0;
}