(C++)二叉树的线索化 / 线索二叉树

  • 好久不见,朋友们!虽然我知道没人看我的博客,但我还是想叨逼叨一下。啊,好久没编程了(其实也就一周没编),但你们知道,程序员一天不编程那能叫程序员么???虽然我不是程序员哈哈哈哈哈,但还是要有基本素养嘛。

  • 继续写二叉树,给自己立一个flag,就是这几天要写完之前没做完的几道题,和二叉树红黑树各种树之类的~~虽然有这个flag,但我还是很实诚地遵从自己的内心,买了一张明天的电影票,等我回来告诉你们好不好看!好看的话,我就!!写影评!!但!!不给看!!

  • 好的,我是屯了很多电影和书没看啦,但我屯的代码好像更多。之前又比较犯懒,就只码代码,没写博客,但我发现哦,写博客真的很有助于增进对代码的分析能力,所以我又开始以我神经兮兮的风格开始写博客啦!

  • 今天我要写的博客是关于二叉树的线索化,当然,也可以理解为是线索二叉树。

线索二叉树

什么是线索二叉树

  • 对于n个结点的二叉树,在二叉链表的数据存储结构中,总是有(2n - (n-1) = n+1)个空链域。
  • 我们利用这些空链域存放某种遍历次序下该结点前驱结点和后续结点的指针,并将这些指针称为线索,称该二叉树为线索二叉树,称给二叉树加上线索的过程为二叉树的线索化

为什么要进行二叉树的线索化

  • 我们都知道,二叉树是一种非线性的数据结构,遍历二叉树时,我们常使用递归或者用栈辅助从而实现非递归的遍历。
  • 显然,当我们使用二叉树作为存储结构时, 取到一个结点,我们只能获取到结点的左右孩子,而无法获取到结点的前驱和后继。
  • 那么,为了进一步增强遍历的实用性,我们利用二叉树结构中的空指针来存放各结点的前驱和后继信息。

线索二叉树的基本设计

这里写图片描述

  • 如果_left为空,则存放指向中序遍历序列中该结点的前驱结点。
  • 如果_right为空,则存放指向中序遍历序列中该结点的后继结点。
  • 如果_leftTag为Link,则代表着结点存放的是其左孩子;存放的是Thread则代表着其存放的是其前驱结点。
  • 如果_rightTag为Link,则代表着结点存放的是其右孩子;存放的是Thread则代表着其存放的是其后继结点。

线索二叉树的实现

中序遍历模型

这里写图片描述

代码实现

#include<iostream>

using namespace std;

//线索化标志Tag
enum PointerTag {THREAD, LINK};

//结点结构
template<class T>
struct BinaryTreeNodeThd
{
    T _data;
    BinaryTreeNodeThd<T>* _left;
    BinaryTreeNodeThd<T>* _right;
    PointerTag _leftTag;
    PointerTag _rightTag;

    //构造函数
    BinaryTreeNodeThd(const T& x)
        :_data(x)
        , _left(NULL)
        , _right(NULL)
        , _leftTag(LINK)
        , _rightTag(LINK)
    {}
};

//基类迭代器
template <class T>
struct __BinaryTreeIterator
{
    typedef BinaryTreeNodeThd<T> Node;
    typedef __BinaryTreeIterator<T> Self;

    Node* _node;

    __BinaryTreeIterator(Node* node)
        :_node(node)
    {}

    T& operator*()
    {
        return _node->_data;
    }

    T* operator->()
    {
        return &(_node->_data);
    }

    bool operator ==(const Self& s)
    {
        return (_node == s._node);
    }

    bool operator != (const Self& s)
    {
        return (_node != s._node);
    }

    virtual Self& operator++() = 0;//纯虚函数
};


//中序遍历迭代器
template<class T>
struct __BinaryTreeInInterator :public __BinaryTreeIterator<T>
{
    typedef BinaryTreeNodeThd<T> Node;
    typedef __BinaryTreeInInterator<T> Self;

    __BinaryTreeInInterator(Node* node)
        :__BinaryTreeIterator(node)
    {}

    Self& operator++()
    {
        if (_node->_rightTag == THREAD)
        {
            _node = _node->_right;
        }
        else
        {
            Node* sub = _node->_right;
            if (sub && sub->_leftTag == LINK)
            {
                sub = sub->_left;
            }
            _node = sub;
        }
        return *this;
    }
};


//前序遍历迭代器
template<class T>
struct __BinaryTreePrevInterator :public __BinaryTreeIterator<T>
{
    typedef BinaryTreeNodeThd<T> Node;
    typedef __BinaryTreePrevInterator<T> Self;

    __BinaryTreePrevInterator(Node* node)
        :__BinaryTreeInterator(node)
    {}

    Self& operator++()
    {
        if (_node->_leftTag == LINK)
        {
            _node = _node->_left;
        }
        else
        {
            _node = _node->_right;
        }
        return *this;
    }

};


//二叉树的线索化
template <class T>
struct BinaryTreeThd
{
    typedef BinaryTreeNodeThd<T> Node;
    typedef __BinaryTreeInInterator<T> InInterator;
    typedef __BinaryTreePrevInterator<T> PrevInterator;

public:
    BinaryTreeThd(T* a, size_t n, const T& invalid)
    {
        size_t index = 0;
        _root = _CreateTree(a, n, index, invalid);
    }

    PrevInterator PrevBegin()
    {
        return root;
    }

    PrevInterator PrevEnd()
    {
        return NULL;
    }

    InInterator InBegin()
    {
        Node* sub = _root;
        while (sub && sub->_leftTag == LINK)
        {
            sub = sub->_left;
        }
        return sub;
    }

    InInterator InEnd()
    {
        return NULL;
    }

    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }

    void InOrderThreading()
    {
        Node* prev = NULL;
        _InOrderThreading(_root, prev);
    }

protected:
    Node* _CreateTree(T* a, size_t n, size_t& index, const T& invalid)
    {
        Node* root = NULL;
        if (index < n && a[index] != invalid)
        {
            root = new Node(a[index]);
            root->_left = _CreateTree(a, n, ++index, invalid);
            root->_right = _CreateTree(a, n, ++index, invalid);
        }
        return root;
    }

    void _InOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        _InOrder(root->_left);
        cout << root->_data << ' ';
        _InOrder(root->_right);
    }

    void _InOrderThreading(Node* root, Node*& prev)
    {
        if (root == NULL)
            return;

        _InOrderThreading(root->_left, prev);

        if (root->_left == NULL)
        {
            root->_left = prev;
            root->_leftTag = THREAD;
        }

        if (prev && prev->_right == NULL)
        {
            prev->_right = root;
            prev->_rightTag = THREAD;
        }
        prev = root;

        _InOrderThreading(root->_right, prev);

    }

private:
    Node* _root;
};

测试用例

void TestBinaryTreeThd()
{
    int a1[] = {1, 2, 3, '#', '#', 4, '#' , '#', 5, 6};
    BinaryTreeThd<int> t1(a1, sizeof(a1)/sizeof(a1[0]), '#');
    t1.InOrder();
    t1.InOrderThreading();

实现结果

这里写图片描述

References

http://blog.csdn.net/u014492609/article/details/40477795
http://blog.csdn.net/my_heart_/article/details/52086321

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树线索化,可以将空指针域利用起来,将二叉树中的空指针指向该节点中序遍历的前驱或后继节点,从而将递归的中序遍历转化为线性的遍历。下面是使用中序线索化完成的中序遍历的C++代码: ```cpp #include<iostream> using namespace std; //定义二叉树结点 struct TreeNode { int val; TreeNode *left; TreeNode *right; bool ltag; //标记左指针是否为线索 bool rtag; //标记右指针是否为线索 TreeNode(int x) : val(x), left(NULL), right(NULL), ltag(false), rtag(false) {} }; //中序线索化二叉树 void InThread(TreeNode* &p, TreeNode* &pre) { if (p != NULL) { InThread(p->left, pre); if (p->left == NULL) { p->ltag = true; p->left = pre; } if (pre != NULL && pre->right == NULL) { pre->rtag = true; pre->right = p; } pre = p; InThread(p->right, pre); } } //中序遍历线索化二叉树 void InThreadOrder(TreeNode* p) { while (p != NULL) { while (p->ltag == false) { p = p->left; } cout << p->val << " "; while (p->rtag == true && p->right != NULL) { p = p->right; cout << p->val << " "; } p = p->right; } } //测试 int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(3); root->left->left = new TreeNode(4); root->left->right = new TreeNode(5); root->right->left = new TreeNode(6); root->right->right = new TreeNode(7); TreeNode* pre = NULL; InThread(root, pre); cout << "中序遍历结果:"; InThreadOrder(root); cout << endl; return 0; } ``` 以上代码中,InThread函数实现了中序线索化,InThreadOrder函数实现了中序遍历线索化二叉树的操作。在main函数中,我们构造了一个简单的二叉树,并进行了中序线索化和中序遍历的测试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值