线索二叉树的理论我也不多说,百度随便搜就有了,但是百度出来的实践全部千篇一律,都参考的同一个人的,故此自己写一份
定义如下:
树节点的定义是完全没必要暴露在外的,故此把它写在ThreadTree内
此示例仅作演示,故就不写template,仅仅用int作为内部存储类型
class ThreadTree
{
struct TreeNode;
using TreeNodePtr = TreeNode*;//与typedef等价的用法
using PointerTag = enum
{
LINK,
THREAD
};//标识左右指针类型
struct TreeNode
{
int val;
TreeNodePtr left;
TreeNodePtr right;
PointerTag lTag;
PointerTag rTag;
explicit TreeNode(int _val) : val(_val), left(nullptr), right(nullptr), lTag(LINK), rTag(LINK)
{
}
};//提示:explicit防止隐式转换,如 TreeNode a = 1;这样的。
private:
TreeNodePtr root;
void insert(int val, TreeNodePtr& node) const;
void buildThread(TreeNodePtr& node, TreeNodePtr& pre) const;
TreeNodePtr first(TreeNodePtr p);
TreeNodePtr next(TreeNodePtr p);
public:
ThreadTree(): root(nullptr)
{
}
ThreadTree(std::initializer_list<int> lis): ThreadTree()//调用无参构造函数省点事
{
for (auto i : lis)
insert(i);
}//此构造函数是方便实现 ThreadTree tree{1,3,4,5,6}这种省事语法.
void insert(int val);
void buildThread();
void inOrderTravelThr();
};
插入:和普通的二叉搜索树一样的
具体的insert实现是private的,仅暴露无参版本的insert,之后演示的函数同理
void ThreadTree::insert(int val, TreeNodePtr& node) const
{
if (node == nullptr)
node = new TreeNode(val);
else
{
if (val > node->val)
{
insert(val, node->right);
}
else if (val < node->val)
{
insert(val, node->left);
}
else
{ //跳过相等的情况,此处不讨论
}
}
}
void ThreadTree::insert(int val)
{
insert(val, root);
}
以下是建立线索,代码参考了天勤版的数据结构考研复习笔记
void ThreadTree::buildThread()
{
TreeNodePtr pre = new TreeNode(0); //根节点的头节点,仅方便函数运行,无实义
if (root != nullptr)
{
buildThread(root, pre);
pre->right = nullptr;
pre->rTag = THREAD;
}
}
//按照中序遍历就行,差别就是中间的操作
void ThreadTree::buildThread(TreeNodePtr& node, TreeNodePtr& pre) const
{
if (node == nullptr)
return;
buildThread(node->left, pre);
if (node->left == nullptr)
{
node->lTag = THREAD;
node->left = pre;
}
if (pre != nullptr && pre->right == nullptr)
{
pre->rTag = THREAD;
pre->right = node;
}
pre = node; //此处注意!!!别以为能省略成buildThread(node->right, node);
//我被这坑了,注意函数形参是&,若不做这部分就会导致其他未收敛的递归过程的pre还是以前的pre。
buildThread(node->right, pre);
}
中序遍历:
ThreadTree::TreeNodePtr ThreadTree::first(TreeNodePtr p)//每次都获取最左边的节点,中序遍历二叉搜索树下是左、根、右,左<根<右
{
if (p != nullptr)
{
while (p->lTag == LINK)
{
p = p->left;
}
}
return p;
}
ThreadTree::TreeNodePtr ThreadTree::next(TreeNodePtr p)
{
if (p->rTag == LINK) //返回当前节点的后继节点,根据tag返回线索或返回右节点
return first(p->right);
return p->right;
}
void ThreadTree::inOrderTravelThr()
{
for (TreeNodePtr p = first(root); p != nullptr; p = next(p))
std::cout << p->val << " ";
}