二叉树及其线索化分析

1. Where did it could work?

/**

*    Q: Where did it could work?

*

*    A: Bin-tree is generally used in deal with work about search or sort. For a  balance tree, it‘s depth is log2(n). That‘s means if we want to find a  node in the tree we need

*        only do choice at most log2(n). This is very exciting compare with the normal search algorithm,which search a node by check nodes one by one. of course, not all of

*        binary trees have this feature, that is depend on the rules what we used to create this tree. By choice varied rules, we could get some amazing result. For example:

*        ordered tree is helpful if we want to get a excellent search performance, or insert a member into a sequence quickly; we use maximum tree to build heap sort; we

*        use the feature of tree to build a Huffman coding and the like.

*

*        Here is an examples about heap sort.

*        http://blog.csdn.net/u012301943/article/details/34136891#t12

*/

2. Have any properties ?

/**

*    Q: Have any properties ?

*

*    A: Though the types of tree is varied, they still have some common features. For a complete binary tree, we could ensure all of it‘s nodes have two child except for leaf

*        node and the parent of the last leaf node. so the features is as following:

*

*            1). if the number of node in the n-th layer is labeled as L(n), then

*                    L(n+1) = L(n) + L(n-1) + ...L(2) + L(1) + 1, except for the last layer.

*

*                Demonstrate this conclusion:

*                    Image this, we have a tree ,which‘s depth is n; In first layer, it have 2^0 nodes;

*                In second layer, it have 2^1 nodes.

*

*                                     O                                    -- 2^0

*                               O          O                              -- 2^1

*                            O    O    O    O                           -- 2^2

*                                      .                                     .

*                                      .                                     .

*                                      .                                     .

*                                      .

*                     O   O   ................    O    O                -- 2^(n-2)

*                 O     O     ................       O     O            -- 2^(n-1)

*

*

*                So, How many nodes in this tree?

*                The answer should as following ,

*

*                    S(n) = 2^0 + 2^1 + ....2^(n-1) = 2^n -1

*                based on this conclusion, we know

*

*                    S(n+1) = 2^(n+1) - 1 = 2^n + 2^n - 1 = 2^n + S(n)

*                    L(n+1) = S(n+1) - S(n) = 2^n -1 + 1 = S(n) + 1

*

*

*            2). Number all of nodes from top to bottom, from left to right. if the number of root node is 1 and we labeled the i-th node as N(i), then we can ensure that

*                        Left child : N(2*i)

*                        right child: N(2*i + 1)

*

*                Demonstrate this conclusion:

*

*                now , we number all of nodes in a tree. Based on our conclusion above , we could to know the number of every node is 2^n + X(n) - 1; X means for

*                the position of this node in corresponding layer.

*

*                                     O                                    -- 2^0 + X0 -1

*                               O          O                              -- 2^1 + X1 -1

*                            O    O    O    O                           -- 2^2 + X2 -1

*                                      .                                     .

*                                      .                                     .

*                                      .                                     .

*                                      .

*                     O   O   ................    O    O                -- 2^(n-2) + X[n-2] - 1

*                 O     O     ................       O     O            -- 2^(n-1) + X[n-1] - 1

*

*                if there is a node W in the i-th layer, we can know it‘s number is

*                    2^(i-1) + X[i-1] -1.

*

*                then the number of right child of W should be

*                    2^i + X[i] - 1.

*

*                it is easy to prove that:

*                    X(i+1) = 2*X(i)

*

*                combine the conclusion above, we could know :

*                    Node            : 2^i + X(i) - 1

*                    Right child     : 2^(i+1) + X[i+1] -1 = 2^(i+1) + 2*X[i] - 1

*                                        =2*(  2^i + X[i] - 1 ) +1

*

*   that‘s means ,

*                    Node          :    i

*                    Right child  :    2*i + 1

*                    Left child    :    2*i

*/

3.How come we want to threaded a tree into a link?

/**

*    Q: How come we want to threaded a tree into a link?

*

*

*    As we all know , generally, our node is like this

*

*            struct node{

*                struct node *lchild;

*                struct node *rchild;

*                DATA data;

*            };

*

*        there are three member. we use @lchild and @rchild to save a pointer to the  node‘s child. But for leaf node, we didn‘t use this region. That is a waste resource.

*

*        Can I reuse those resources ?

*

*        Of course, we can. Think about this: How can we throughout a tree?

*

*        Recursion is a common way. Actually, what we really need is a stack, which  have a feature of first-in and last-out. So we have two choices if we want to throughout

*    a tree. First method is use function recursion. In this case, the system will automaticlly  create a stack for us. Second method, create a stack and manage it by ourself.

*    No matter what we choice, the cost is still expensive. Now, we have some idle  resources.Some people introduce a method to use those resources to solve this

*    problem. when we want to throughout a tree, this way can protect us from the  expensive recursion operation. In other words, we can use some idle resources to

*    improve our binary tree.

*/

4. How can we create a threaded tree ?

/**

*    Q: How can we create a threaded tree ?

*

*    A: First at all, some bad news need to clarify. As we all know, we have three  kinds of ergodic order: preorder, inorder and postorder. If we want to create a

*        threaded tree They must be have different requests for idle resources. On the other  hand, we have two types of threaded tree: towards to back, toward to

*        head. They have different requests to idle resources too . In a word, we have the following conclusion:

*

*            1). For inorder traversal, the idle resources is match with the  requests. We can create two types of threaded tree: toward to back and toward to head.

*            2). For preorder traversal, the situation is become awful. We can only create the threaded tree that toward to back.

*            3). For postorder traversal, we can only create the threaded tree that  toward to head.

*

*        (Need to say, there are some trick to cover this problem, but difficult.)

*        we should have demonstrated the conclusion above, explain it as clear and simple as possible, but, unfortunately,that is out of my league. All of the text above is

*        just want to clarify a fact: we can‘t create a threaded tree always, sometime it is difficult since we haven‘t a match  idle resource. Now, It time to return our issue.

*       Actually, the process of initialize a threaded tree is simple. What we need to do is just through a  tree by a order, and initialize some idle region in some nodes.

*/

5. source code

/*

*        Here is a simple source code about the threaded binary tree. There are many problem in it. But easy on it, it just a example:

*/

#include <stdio.h>

typedef int    INDEX;
enum ORDER {
        OR_PRE,
        OR_POST,
        OR_IN,
        OR_INVALIED,
};

/**
*    The node of a tree. Because it's data region is unknown, we build a
*    template class to ensure it can match with different data element.
*/
template <class ELEM>
class NODE {
        public:
                NODE<ELEM>    *left;
                NODE<ELEM>    *right;
                ELEM                    ele;
                /*
            *    In a threaded tree, we need two tags to ensure the status of pointer region.
            */
                bool        rtag;
                bool        ltag;
};
/**
*    the type of data region. For uniform the use of target data, Here define
*    a macro.
*/
#define ELEMENT	char

/**
*    This is a common interface for user do some operation. It is defined by
*    user and called by every node when do a throughout traversal.
*/
typedef bool (*CallBack)( NODE<ELEMENT> *data);

/**
*    The core class, it is provide some operation that is needed by deal with the
*    binary tree . some of non-core operation is not defined.
*/
class BTREE:public NODE<ELEMENT> {
        public:
                BTREE( );
                ~BTREE( );
                /*
            *    Create a tree by a string.
            */
                bool CreateBTree( char *);
                bool DestroyBTree( );
                bool EmptyBTree( );
                /*
            *    Three types of ergodic : inorder, preorder and postorder. In inorder traversal,
            *    we will initialize those idle region of nodes to create a threaded tree.
            */
                bool InOrder( CallBack func);
                bool PreOrder( CallBack func);
                bool PostOrder( CallBack func);
                /*
            *    After do a inorder traversal, a threaded tree will be created automatically..
            *    Of course, It is a inorder threaded tree. Based on those data, we can
            *    do a inorder traversal simply, no longer need recursion operation.
            */
                bool InOrder_th( CallBack func);

        private:
                /*
            *    used to create a tree by a string.
            */
                bool createSubTree( char *tree, INDEX &pos, NODE<ELEMENT> **p_child);
                /*
            *    Normally, we traverse a tree by recursion operation. The following is
            *    the recursion function corresponding to different order .
            */
                bool _InOrder( CallBack func, NODE<ELEMENT> *nod);
                bool _PreOrder( CallBack func, NODE<ELEMENT> *nod);
                bool _PostOrder( CallBack func, NODE<ELEMENT> *nod);
                /*
            *    used to create a link between two nodes.
            */
                bool _CreateLink( NODE<ELEMENT> *nod, NODE<ELEMENT> *last);
                /*
            *    point to root node.
            */
                NODE<ELEMENT>    *root;
                /*
            *    In general, It is a invalied value. After do a traversal, we will create
            *    a threaded tree , this member is used to record what kind of current
            *    threaded tree. This is important, since different threaded tree have
            *    a different rules for use.
            */
                ORDER        order;
                /*
            *    we record every node which we was arrived at last time. So when we
            *    arrive a new node, if necessary, we can create a link between those
            *    two nodes .
            */
                 NODE<ELEMENT>    *last;
                /*
            *    A threaded tree have a head node and it is not always the root node.
            *    So it is needful to have a pointer to this head node.
            */
                NODE<ELEMENT>    *head;
                /*
            *    This is the end node of a threaded tree. Sometime we maybe want to
            *    traversal a tree by reversed direction.
            */
                NODE<ELEMENT>    *end;
};

BTREE::BTREE( )
{
        this->root = NULL;
        this->order = OR_INVALIED;
        this->last = NULL;
        this->head = NULL;
        this->end = NULL;
}

BTREE::~BTREE( )
{
        if( this->root!=NULL)
        {
                this->DestroyBTree( );
                this->root = NULL;
                this->last = NULL;
                this->head = NULL;
                this->end = NULL;
        }
}

/*
*    create a tree.
*/
bool BTREE::CreateBTree( char *tree)
{

        INDEX    pos = 0;
        return this->createSubTree( tree, pos, &this->root);
}

bool BTREE::DestroyBTree( )
{
        return false;
}

bool BTREE::EmptyBTree( )
{
        return false;
}

/**
*    Create a tree by a string.
*/
bool BTREE::createSubTree( char *tree, INDEX &pos, NODE<ELEMENT> **p_child)
{
        /*
       *    if we encounter a '\0' or ' ', that's means this branch is NULL.
       */
        if( (tree[pos]!='\0')
                &&(tree[pos]!=' ') )
        {
                /*
            *    create a node for this normal char. Then we will try to create it's child.
            *    Of cource, if the following char is a abnormal char, that's means there
            *    are no child for this node.
            */
                *p_child = new NODE<ELEMENT>;
                (*p_child)->ele = tree[pos];
                (*p_child)->left = NULL;
                (*p_child)->right = NULL;
                (*p_child)->rtag = false;
                (*p_child)->ltag = false;
                /*
            *    recur to create sub-tree.
            */
                pos++;
                this->createSubTree( tree, pos, &(*p_child)->left);
                pos ++;
                this->createSubTree( tree, pos, &(*p_child)->right);

                return true;
        }

        *p_child = NULL;
        return false;
}

bool BTREE::InOrder( CallBack func)
{
        this->last = NULL;
        if( this->_InOrder( func, this->root))
        {
                this->order = OR_IN;
                return true;
        }
        else
        {
                this->order = OR_INVALIED;
                return false;
        }
}

bool BTREE::_InOrder( CallBack func, NODE<ELEMENT> *nod)
{

        if( nod!=NULL)
        {
                if( !nod->ltag)
                        this->_InOrder( func, nod->left);

                if( func!=NULL)
                        func( nod);
                //create link
                this->_CreateLink( nod, this->last);
                //save the head of nodes.
                if( this->last==NULL)
                {
                        this->head = nod;
                }
                this->last = nod;

                if( !nod->rtag)
                        this->_InOrder( func, nod->right);

                return true;
        }

        return false;
}

bool BTREE::_CreateLink( NODE<ELEMENT> *nod, NODE<ELEMENT> *last )
{
        nod->ltag = false;
        nod->rtag = false;
        if( nod->left==NULL)
        {
                nod ->left = last;
                nod->ltag = true;
        }
        if( ( last!=NULL)
                &&(last->right==NULL))
        {
                last->right = nod;
                last->rtag = true;
        }

        return true;
}

bool BTREE::PostOrder( CallBack func)
{

        if( this->_PostOrder( func, this->root) )
        {
                this->order = OR_POST;
                return true;
        }
        else
        {
                this->order = OR_INVALIED;
                return false;
        }
}

bool BTREE::_PostOrder(CallBack func,NODE < ELEMENT > * nod)
{
        if( nod!=NULL)
        {
                if( !nod->ltag)
                        this->_PostOrder( func, nod->left);
                if( !nod->rtag )
                        this->_PostOrder( func, nod->right);

                if( func!=NULL)
                        func( nod);

                return true;
        }

        return false;
}

bool BTREE::PreOrder( CallBack func)
{
        if( this->_PreOrder( func, this->root) )
        {
                this->order = OR_PRE;
                return true;
        }
        else
        {
                this->order = OR_INVALIED;
                return false;
        }
}

bool BTREE::_PreOrder( CallBack func,NODE < ELEMENT > * nod)
{
        if( nod!=NULL)
        {
                if( func!=NULL)
                        func( nod);
                if( !nod->ltag )
                        this->_PreOrder( func, nod->left);

                if( !nod->rtag)
                        this->_PreOrder( func, nod->right);

                return true;
        }
        return false;
}

/**
*    compare this with the normal traversal function , the recursion function
*    are avoided.
*/
bool BTREE::InOrder_th(CallBack func)
{
        if( this->order!=OR_IN)
        {
                return false;
        }

        NODE<ELEMENT> *cur = this->head;
        while( cur!=NULL)
        {
                if( func!=NULL)
                        func( cur);

                if( cur->rtag )
                {
                        cur = cur->right;
                }
                else
                {//find smallest one in right branch.
                        cur = cur->right;
                        while( (cur!=NULL)
                                && (!cur->ltag) )
                        {
                                cur = cur->left;
                        }
                }
        }

        return true;
}

bool show( NODE<ELEMENT> *data)
{
        printf(" %c ", data->ele);
        fflush( stdin);
        //getchar();
        return true;
}

/**
*    based on our rules, we will create a tree like this.
*
*                    [1]
*                 /       *              [2]         [3]
*             /   \        /  *          [4]   [5]   [6]  [7]
*         /   *      [8]    [9]
*
*/
#define TREE	"1248  9  5  36  7  "
/***/

int main()
{
        BTREE    tree;
        tree.CreateBTree( TREE);
        tree.InOrder( show);
        printf("\n");
        tree.InOrder_th( show);
        printf("\n");
        tree.PreOrder( show);
        printf("\n");
        tree.PostOrder( show);
        printf("\n");

        return 0;
}

二叉树及其线索化分析

时间: 2024-08-05 19:37:46

二叉树及其线索化分析的相关文章

二叉树的线索化算法思想详解

二叉树的线索化,这几天以来我很难掌握,今天终于想通了,哈哈,首先我们来看看二叉树线索化之后会变成什么样子,这里我们以图中的二叉树为例,图如下: 画的太糙,各位看官讲究着看吧- -.所谓二叉树的线索化,就是当一个节点的左右指针为空时,就让它的左右指针指向该节点的前驱或者后继(一般来说左指针指向前驱,右指针指向后继).这里不论指向前驱或者后继,我们都应该线索化时,至少要明确两个节点指针的值,当前节点和当前节点的前驱/后继.这也是线索化的两种思路: 保存前驱:访问当前节点时若当前节点的左指针为空,则令

二叉树的层序遍历和二叉树的线索化

先根,后子树:先左子树,后右子树 二叉树的根节点 a 入队 a 的子树,根节点 b 和 c 分别入队 然后 b 的子树的根节点入队(为空) c 的子树的根节点入队 d 的子树的根节点入队(为空) e 的子树的根节点入队 f 的子树的根节点入队(为空) g的子树的根节点入队(为空)结束层序遍历,整个过程就是一层层的遍历,依靠一个队列来存放临时查找的结点. 二叉树线索化 问题的提出:当以二叉链表作为存储结构时,只能找到结点的左右孩子的信息,而不能直接找到结点的任一序列的前驱与后继信息,这种信息只有在

6.3线索二叉树(二叉树的线索化)

6.3线索二叉树(二叉树的线索化) 问题引入:以二叉链表作为存储结构时,只能得到结点的左.右孩子的信息,不能得到直接前驱.后继的信息. 问题解决:将二叉树线索化. 实现原理:n个结点的二叉树具有n+1个空指针域,利用这些空指针域存储结点的前驱.后继信息. 实质:线索化的实质是将二叉链表中的空指针改为指向前驱.后继的线索. (1)二叉树的存储表示 enum {link,thread};//link=0; thread=1; typedef struct bintree { char data; s

树——二叉树的线索化

1,什么是线索化二叉树? 1,将二叉树转换为双向链表的过程(非线性 ==> 线性): 1,实际工程开发中,很大一部分情况下,二叉树一旦建立之后,就不会轻易改动,一般的用于遍历,并且这种操作一般执行很多: 2,先中后序遍历都是递归完成的,实际工程开发中,对一棵已经建立的二叉树反复执行先序遍历,效率低,所以不推荐反复的递归的遍历: 3,直接将遍历后的结果保存下来,下一次遍历直接用这个结果就可以: 4,工程开发中还有一种常见情况,就是要反复的知道某个结点在中序遍历下,前驱结点是谁.后继结点是谁,需要这

二叉树的线索化

---恢复内容开始--- 遍历二叉树是以一定规则将二叉树中结点排列成一个线性序列即是对一个非线性结构进行线性化操作,使除第一个和最后一个节点外,每一个节点有且只有一个直接前驱,直接后继 二叉树作为存储结构只能找到节点的左孩子右孩子信息,而不能直接得到结点在任一序列中的前驱和后继,这种信息只有在遍历的动态过程中可以看到. 二叉树线索化可以利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息可以使用以下结点结构: enum pointertag{ Link, Thread };template

数据结构--二叉树的线索化

线索二叉树它解决了无法直接找到该结点在某种遍历序列中的前趋和后继结点的问题,出现了二叉链表找左.右孩子困难的问题,线索二叉树又分为前序线索化,中序线索化和后序线索化,分别用不同的逻辑去实现. 线索二叉树的实现思想:借用一个枚举类型tag其中包含两个状态Link(代表有数据),thread(代表下一个节点为空)在一个节点的左节点或者右节点为空的情况下,将它的left或right设为thread,则它的左或右访问的是改遍历模式下访问到的下一个节点数据,这样就完成了跳到另一颗子树的过程,减少了递归的次

第六十九课 二叉树的线索化实现

在工程中,很多时候二叉树一旦建立就不会轻易改动,这样的二叉树就用于遍历,我们讲了先序遍历.中序遍历.后续遍历三种方式,都是递归完成的,在工程中,如果对一棵二叉树反复的执行遍历,效率很低,递归的效率是比较低的. 改进的做法就是将遍历的结果保存下来,下一次遍历时直接用这个结果. 在工程中另一种需求就是,在中序遍历下,需要知道某一个节点的前驱是谁,后继是谁,需要这三个节点来判断是否执行后续的操作.这个时候又需要遍历了.每次都递归的进行遍历,效率太低了. 为了效率,我们使用线索化二叉树的方法,将二叉树转

c++ 二叉树的线索化(前中后序遍历)

#pragma once//.hpp函数头文件 #include<iostream> using namespace std; enum BinTreeNodeChildType { Thread, Link }; template <class T> struct BinaryTreeThrNode { public: T _data;  //数据域 BinaryTreeThrNode<T>* _leftChild;//做孩子 BinaryTreeThrNode<

二叉树之线索二叉树

相对于顺序存储结构而言,利用链式存储结构的二叉树已经有了很高的存储效率,单是还是有空间上未利用到的地方,比如说叶子结点的左右孩子是空的,指向左右孩子的指针就是空闲的,没有被利用到:而且,有时候给定一个结点,我们需要查找该结点的前驱结点和后继结点,如果按照中序遍历的做法去查找的话,对于一个非叶子结点,其前驱和后继结点查找可以以下算法: 1.preNode=node.left;//前去结点就是该结点的左孩子 2.subNode=search(node.right)://后继结点是该结点的右子树的最左