线索二叉树

这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
注意:
线索链表解决了无法直接找到该结点在某种遍历序列中的前趋和后继结点的问题,出现了二叉链表找左、右孩子困难的问题。
二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)。对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。为了容易找到前驱和后继,有两种方法。一是在结点结构中增加向前和向后的指针fwd和bkd,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。现将二叉树的结点结构重新定义如下:
lchild
ltag
data
rtag
rchild
其中:ltag=0 时lchild指向左子女;
ltag=1 时lchild指向前驱;
rtag=0 时rchild指向右子女;
rtag=1 时rchild指向后继;
建立线索二叉树,或者说对二叉树线索化,实质上就是遍历一颗二叉树。在遍历过程中,访问结点的操作是检查当前的左,右指针域是否为空,将它们改为指向前驱结点或后续结点的线索。为实现这一过程,设指针pre始终指向刚刚访问的结点,即若指针p指向当前结点,则pre指向它的前驱,以便设线索。
另外,在对一颗二叉树加线索时,必须首先申请一个头结点,建立头结点与二叉树的根结点的指向关系,对二叉树线索化后,还需建立最后一个结点与头结点之间的线索。

 

  class BinaryTree
    {
        private BinaryTreeNode _head;//头指针
        private BinaryTreeNode pre;//记录当前结点的前一结点
        private string cStr;//用于构造 二叉树

        public BinaryTreeNode Head
        {
            get {return _head ;}
        }

        public BinaryTree(string Str)
        {
            cStr = Str;
            _head = new BinaryTreeNode(cStr[0]);//添加头结点
            ADD(_head,0);
            pre = null;
            MidOrderThread(_head);//线索化

        }

        private void ADD(BinaryTreeNode parent, int p)
        {
            int leftIndex = 2 * p + 1;//左孩子的索引位置
            if (leftIndex<cStr.Length)
            {
                if (cStr[leftIndex]!='#')//为非空结点
                {
                    parent.Left = new BinaryTreeNode(cStr[leftIndex]);
                    ADD(parent.Left, leftIndex);
                }
            }



            int rightIndex = 2 * p + 2;
            if (rightIndex < cStr.Length)
            {
                if (cStr[rightIndex] != '#')//为非空结点
                {
                    parent.Right = new BinaryTreeNode(cStr[rightIndex]);
                    ADD(parent.Right, rightIndex);
                }
            }
        }



        private void MidOrderThread(BinaryTreeNode node)//中序线索化
        {
            if (node!=null)//不为空树
            {
                MidOrderThread(node.Left);//递归遍历左孩子结点
                if (node.Left==null)
                {//左孩子的指针域为空
                    node.Ltag = 1;//左线索标识为1
                    node.Left = pre;//左孩子指针指向前驱结点
                }
                if (pre!=null&&pre.Right==null)
                {
                    pre.Rtag = 1;
                    pre.Right = node;
                }
                pre = node;
                MidOrderThread(node.Right);
            }
        }


        public  void MidOrder()//线索二叉树的遍历
        {
            BinaryTreeNode p = _head;
            while (p.Left!=null)//获得中序遍历的第一个结点
            {
                p = p.Left;
            }
            do
            {
                Console.WriteLine("{0,-3}{1,3}{2,-3}",p.GetPrev(),p,p.GetNext());
                p = p.GetNext();
            } while (p!=null);
        }
    }
 public  class BinaryTreeNode
    {
        private object _data;//数据
        private BinaryTreeNode _left;//左孩子
        private int _ltag;//左线索标识
        private BinaryTreeNode _right;//右孩子
        private int _rtag;//右线索标识

        public object Data
        {
            get {return _data ;}
        }

        public BinaryTreeNode Left
        {
            get { return _left;}
            set { _left=value;}
        }
        public BinaryTreeNode Right
        {
            get { return _right; }
            set { _right = value; }
        }

        public BinaryTreeNode(object data)
        {
            _data = data;
        }

        public override string ToString()
        {
            return _data.ToString();
        }

        public int Ltag
        {
            set { _ltag=value;}
            get { return _ltag ;}
        }
        public int Rtag
        {
            set { _rtag = value; }
            get { return _rtag; }
        }


        public BinaryTreeNode GetPrev()//获取前驱结点
        {
            if (_ltag==1)//如果左标识为1,代表左指针存放的是前驱结点
            {
                return _left;
            }
            else//如果左标识为1,代表左指针存放的是左孩子结点
            {
                BinaryTreeNode tmp = _left;
                while (tmp._rtag==0 )//找到最后一个含有右孩子的结点 
                {
                    tmp = tmp._right;
                }
                return tmp;
            }
        }


        public BinaryTreeNode GetNext()//获得后继结点
        {
            //如果右线索标识为1,Right存放的是后继结点
            if (_rtag==1)
            {
                return _right;
            }
            else
            {
                BinaryTreeNode tmp = _right;
                while (tmp!=null&&tmp._ltag==0)
                {//找到右子树的最左下角结点
                    tmp = _left;
                }
                return tmp;
            }

        }
    }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication14
{
    class Program
    {
        static void Main(string[] args)
        {
            BinaryTree tree = new BinaryTree("ABCDE#F");
            tree.MidOrder();
            Console.ReadLine();


        }
    }
}

posted @ 2014-07-06 23:10  欢呼雀跃  阅读(321)  评论(0)    收藏  举报