【数据结构】线索化二叉树中序线索化的递归写法和非递归写法

二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历。用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继。

为了保存这种在遍历中需要的信息,我们利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息。所以引入了线索化二叉树。下面我们讲一下线索化二叉树中序线索化的两种实现方法:

(1).递归实现中序线索化二叉树

首先我们先看一下线索化二叉树的结构

enum PointerTag{ THREAD, LINK };

template<class T>
struct BinaryTreeThdNode
{
    BinaryTreeThdNode<T>* _left;
    BinaryTreeThdNode<T>* _right;
    PointerTag _leftTag;
    PointerTag _rightTag;
    T _data;

    BinaryTreeThdNode(const T& x)
        :_left(NULL)
        , _right(NULL)
        , _leftTag(LINK)
        , _rightTag(LINK)
        , _data(x)
    {}
};

用递归实现中序线索化二叉树,主要有两个需要注意到地方。

首先我们先递归左。但是要考虑递归的条件是什么,只有当左右的标识符为THREAD的时候我们才能递归,否则会无限循环,因为左右为空的节点会指向前一个节点和后一个节点,从而引发无限递归。这个可以自己下去试验一下。

另外一个需要注意的点就需要在自己分析问题的时候遇到的,就是当我们的右节点为空时,我们需要将右节点连接到上一层递归的节点上去。既然是递归下来的,那么上一层就相当于未来一样的,我们是无法预知的,那么怎么才能将右边连接到上一层的节点上去呢?

嘿嘿,既然我们不能从现在去到未来,那么到未来的时候,我们再来做这件是嘛!我们先将这个时间节点记住,把他记作prev当我们到他的上一层节点的时候,先判断一下prev是不是为NULL的并且判断一下他是不是需要THREAD的(线索化的)。如果是,那么把保存的prev节点的右指向当前的节点就行了。

然后再递归右,这样就完成了线索话二叉树。

template<class T>
class BinaryTreeThd
{
    typedef BinaryTreeThdNode<T> Node;
public:
    BinaryTreeThd(int* a, size_t size, const T& invalid)
    {
        size_t index = 0;
        _root = _CreateTreeThd(a, size, invalid,index);
    }
    
    Node* _CreateTreeThd(int* a, size_t size, const T& invalid, size_t& index)
    {
        Node* root = NULL;
        if (index < size && a[index] != invalid)
        {
            root = new Node(a[index]);
            root->_left = _CreateTreeThd(a, size, invalid, ++index);
            root->_right = _CreateTreeThd(a, size, invalid, ++index);
        }

        return root;
    }
    
//用递归实现线索化二叉树
    void InOrderThreading()
    {
        Node* prev = NULL;
        _InOrderThreading(_root,prev);
    }
    
    protected:
    //递归实现线索化二叉树
    void _InOrderThreading(Node* root,Node* prev)
    {
        if (root == NULL)
            return;

        if (root->_leftTag == LINK)
        _InOrderThreading(root->_left, prev);

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

        prev = root;

        if (root->_rightTag == LINK)
        _InOrderThreading(root->_right, prev);
    }

(2).用栈实现中序线索化二叉树

用栈实现线索化二叉树就没有递归那么抽象了,思路跟递归的差不多,只是我们不再需要考虑上一层访问不到的问题了,因为栈取栈顶就能知道上一层的节点了。这种写法,自己去画图倒一下就能理解啦。这里我就只给出代码了。

/*用栈线索化二叉树*/
    void InOrderThreading()
    {
        stack<Node*> s;
        Node* prev = NULL;
        Node* cur = _root;
        while (cur || !s.empty())
        {
            while (cur)
            {
                s.push(cur);
                cur = cur->_left;
            }
            cur = s.top();
            s.pop();
            if (cur->_left == NULL)
            {
                cur->_left = prev;
                cur->_leftTag = THREAD;
            }
            prev = cur;
            if (cur->_right == NULL && !s.empty())
            {
                cur->_right = s.top();
                cur->_rightTag = THREAD;
                cur = NULL;
            }

            else
            {
                cur = cur->_right;
            }
        }
    }

另加两种打印方法:

(1).递归打印

void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }  
    
    //递归打印线索化二叉树
    void _InOrder(Node* root)
    {
        if (root == NULL)
            return;
        if (root->_leftTag == LINK)
            _InOrder(root->_left);

        cout << root->_data << " ";
        if (root->_rightTag == LINK)
        {
            _InOrder(root->_right);
        }
    
    }

(2).用栈打印

void InOrder()
    {
        if (_root == NULL)
            return;
        Node* cur = _root;
        while (cur)
        {
            while (cur->_left)
            {
                cur = cur->_left;
            }
            cut << cur->_data << " ";
            if (cur->_rightTag == THREAD)
            {
                cout << cur->_right->_data << " ";
                cur = cur->_right;
            }
            else if (cur->_right == LINK)
            {
                
            }
        }
    }

时间: 2024-07-31 14:27:03

【数据结构】线索化二叉树中序线索化的递归写法和非递归写法的相关文章

数据结构例程——线索化二叉树(中序)

本文是数据结构基础系列(6):树和二叉树中第14课时线索二叉树的例程. #include <stdio.h> #include <malloc.h> #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; int ltag,rtag; //增加的线索标记 struct node *lchild; struct node *rchild; } TBTNode; void Creat

java实现线索化二叉树的前序、中序、后续的遍历(完整代码)

java实现线索化二叉树的前序.中序.后续的遍历 比如创建一个二叉树 1 / 3 6 / \ / 8 10 14 线索化二叉树几个概念: n个节点的二叉链表中含有n+1 [公式2n-(n-1)=n+1]个空指针域.利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加指针成为线索).如下面的就是6+1=7个空指针域 (8,10,14各有连个指针没有指向 6有一个) 加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树.分为前序线索二叉树.中序线索二叉树.

数据结构与算法---线索化二叉树(Threaded BinaryTree)

先看一个问题 将数列 {1, 3, 6, 8, 10, 14  } 构建成一颗二叉树 问题分析: 当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 } 但是 6, 8, 10, 14 这几个节点的 左右指针,并没有完全的利用上. 如果我们希望充分的利用 各个节点的左右指针, 让各个节点可以指向自己的前后节点,怎么办? 解决方案-线索二叉树 线索二叉树基本介绍 1.n个结点的二叉链表中含有n+1  [公式 2n-(n-1)=n+1] 个空指针域.利用二叉链表中的空

线索化二叉树的构建与先序,中序遍历(C++版)

贴出学习C++数据结构线索化二叉树的过程, 方便和我一样的新手进行测试和学习 同时欢迎各位大神纠正. 不同与普通二叉树的地方会用背景色填充 //BinTreeNode_Thr.h 1 enum PointTag 2 {Link,Thread}; 3 4 template<typename ElemType> 5 struct BinTreeNode 6 { 7 ElemType data; //数据元素 8 PointTag LTag,RTag; //左标志,右标志 9 BinTreeNode

中序线索化二叉树

中序线索化二叉树 1 void Tree::_inTree(Node * root, Node * &pre) { 2 if (root == NULL) { // 结点为空, 1:二叉树为空 2:已到达右子树的最后一个右结点的 rchild 3 return; 4 } 5 _inTree(root->lchild, pre); // 到达当前结点的左子树的底部左结点 6 if (root->lchild == NULL) { 7 root->ltag = nChild; //

中序线索化二叉树[C语言实现及注释]

根据我自己的理解给代码加了注释. /* 中序线索二叉树 2014/11/14 */ #include<stdio.h> #include<stdlib.h> typedef struct BiTrNoDe{ char data; struct BiTrNoDe *lchild; struct BiTrNoDe *rchild; unsigned ltag : 1; //LINK是1 此处也可以用枚举类型或者宏定义去写 unsigned rtag : 1; //threading是0

数据结构 树的创建(线索化二叉树)

//二叉树的线索化 #include<stdio.h> #include<stdlib.h> #include<string.h> //定义二叉树线索化节点 typedef struct _TreeNode{ char data; char lefttag;//0表示没有线索化,1表示线索化---每次创建节点都会初始化 所以所有节点默认都是0 char righttag; struct _TreeNode * leftchild; struct _TreeNode *

【算法与数据结构】二叉树 中序线索

中序线索二叉树 /************************************************************************ 线索二叉树 二叉树的节点有五部分构造 ----------------------------------------- | lChild | lTag | value | rTag | rChild | ----------------------------------------- lChild = (lTag == 0 ? 左

二叉树的中序线索化以及遍历

#include <stdio.h> #include <stdlib.h> typedef struct Node { char data; int Ltag; struct Node* LChild; int Rtag; struct Node* RChild; }BitNode, * BiTree; //先序创建二叉树 void CreatBiTree(BiTree* root) { char ch; ch = getchar(); if (ch == '.') *root