线索二叉树,看这一篇就够了

本文章是我看完《大话数据结构》总结的,加了自己的理解和代码
本文章适合稍微了解线索二叉树的人

线索二叉树
  • 线索二叉树相当于双向链表,知道一个结点便可得出前驱和后继(这里指按某种遍历的前驱和后继)
  • 如果所用的二叉树需经常遍历或查找结点时需要某种遍历序列中的前驱和后继,那么采用线索二叉链表的存储结构就是非常不错的选择
  • 注意:先有一颗完整的树才能进行线索化
  • 线索化指充分利用原来指向为NULL的,如果其为左孩子或右孩子,则
    • 左孩子指向前驱
    • 右孩纸指向后继
  • 线索二叉树
struct TreeNode {
    int val;
    TreeNode* lchild;
    TreeNode* rchild;
    bool lTag = Link;//Link 表示左右孩纸指针,Thread 表示指向前驱或者后继的线索
    bool rTag = Link;//初始化默认为Link
}
中序线索二叉树
中序线索化
class Solution {
    TreeNode* pre = NULL;//属性全局变量,指向前驱
    void inorderThread(TreeNode* cur) {
        if (cur == NULL) return;
        inorderThead(cur->lchild);
        if (cur->lchild == NULL) {//没有左孩子,线索化,指向前驱pre
            cur->lTag == Thread;
            cur->lchild = pre; 
        }
        if (pre != NULL && pre->rchild == NULL) {//前驱没有后孩子,那么指向后继(即现在访问的)
            pre->rchild = cur;
            pre->rTag = Thread;
        }
        pre = cur;//更新
        inorderThead(cur->rchild);
    }
};
  • 经过线索化后,会有两个NULL,一个是中序遍历第一个结点的左孩子,和最后一个结点的右孩子
    请添加图片描述
中序线索化加虚拟头节点

请添加图片描述

class Solution {
    TreeNode* dummyHead = new TreeNode;
    dummyHead->lchild == cur;//虚拟头结点的左孩子指向根结点
    void inorderAddThread(TreeNode* cur) {
        if (cur == NULL) return;
        inorderAddThread(cur->lchild);
        //令中序遍历第一个结点的 左孩子指向虚拟头节点
        if (cur->lchild == NULL) {
            cur->lTag = Thread;
            cur->lchild = dummyHead;
        }
        //令中序遍历的最后一个结点的右孩子指向虚拟头节点,且头节点的右孩纸指向最后一个结点
        if (cur->rchild == NULL) {
            cur->rTag = Thread;
            cur->rchild = dummyHead;
            dummyHead->rchild = cur;
        }
        inorderAddThread(cur->rchild);
    }
};
迭代顺序遍历中序线索二叉树
  • 其实是模拟递归,先到最左,但是因为迭代无法回溯,利用后驱遍历下一个(即中间),然后再转右孩子。本质是模拟递归
  • 迭代顺序遍历利用的是后继
    顺序遍历:从第一个结点顺后继继续遍历
class Solution {
    vector<TreeNode*> inorderTraversal(TreeNode* dummyHead) {
        vector<TreeNode*> result;
        //指向根节点
        ThreeNode* cur = dummyHead->lchild;
        while (cur != dummyHead) {
            //找到中序遍历第一个结点(向左找到无左孩子的结点)
            while (cur->lTag == Link){
                cur = cur->lchild;
            }
            result.push_back(cur);
            //利用后继指针遍历下一个结点
            while (cur->rTag == Thread && cur->rchild != dummyHead) {
                cur = cur->rchild;
                result.push_back(cur);
            }
            //转向右孩子
            cur = cur->rchild;
        }
        return result;
    }
}
迭代倒序遍历中序线索二叉树
  • 迭代倒序遍历利用的是前驱
    倒序遍历:从最后一个结点起顺前驱进行遍历
class Solution {
    vector<TreeNode*> inorderTraversal(TreeNode* dummyHead) {
        vector<TreeNode*> result;
        //指向根节点
        ThreeNode* cur = dummyHead->lchild;
        //或者直接cur = dummyHead->rchild;//直接指向中序遍历倒数第一个结点
        while (cur != dummyHead) {
            //向右到没有右的地方
            while (cur->rTag == Link){
                cur = cur->rchild;
            }
            result.push_back(cur);
            //利用前驱指向前一个
            while (cur->lTag == Thread && cur->lchild != dummyHead) {
                cur = cur->lchild;
                result.push_back(cur);
            }
            //跳到左孩子
            cur = cur->lchild;
        }
        return result;
}
除此外,还有前序和后序线索二叉树,原理一样,以后有时间来填坑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值