线索二叉树的建立与遍历

线索二叉树的理论我也不多说,百度随便搜就有了,但是百度出来的实践全部千篇一律,都参考的同一个人的,故此自己写一份

定义如下:
树节点的定义是完全没必要暴露在外的,故此把它写在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 << " ";
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值