线索二叉树

来源:互联网 发布:骑士vs火箭数据 编辑:程序博客网 时间:2024/06/06 04:00
一,什么是线索二叉树
在有n个结点的二叉链表中必定存在n+1个空指针域,因此可以利用这些空指针域存放指向结点的某种遍历次序下的前趋和后继结点的指针,这种指向前趋和后继结点的指针称为“线索”,加上线索的二叉链表称为线索链表,相应的二叉树被称为线索二叉树。

二,为什么要建立线索二叉树
有了二叉树不就足够了吗?那为什么还要弄个线索二叉树出来呢?
在原来的二叉链表中,查找结点的左,右孩子可以直接实现,可是如果要找该结点的前趋和后继结点呢?这就变得非常困难,所以为了实现这个常见的需求,我们要在每个结点中增加两个指针域来存放遍历时得到的前趋和后继结点,这样就可以通过该指针直接或间接访问其前趋和后继结点。

三,如何将二叉树线索化
按某种次序遍历二叉树,在遍历过程中用线索取代空指针即可。

下面是线索二叉树和线索二叉链表示意图,它可以帮助我们更好地理解线索二叉树。


四,线索二叉树的常见操作及实现思路
1,二叉树线索化
实现思路:按某种次序遍历二叉树,在遍历过程中用线索取代空指针即可。
2,查找后继节点
实现思路:分两种情况,一,没有右孩子,直接获取。二,有右孩子,中序遍历查找右子树中序遍历的第一个节点即为当前节点的后继节点。
3,查找前驱节点
实现思路:同样也分两种情况,一,没有左孩子,依据线索直接获取。二,有左孩子,中序遍历左子树中往右链中第一个没有右孩子的节点即为前驱节点
4,遍历
实现思路:以中序遍历为例,首先找到中序遍历的开始节点,然后利用线索依次查找后继节点即可。

namespace DS.BLL{    /// <summary>    /// Description:线索二叉树业务逻辑类    /// Author:McgradyLu    /// Time:9/10/2013 10:27:38 PM    /// </summary>    public class BinTreeThreadBLL    {        /// <summary>        /// 创建线索二叉树(利用中序)        /// 思路:利用中序遍历,用线索取代空指针        /// </summary>        /// <typeparam name="T">数据类型</typeparam>        /// <param name="tree">待操作线索二叉树</param>        /// <param name="prevNode">当前节点前驱</param>        public static void CreateByLDR<T>(ref BinTreeThread<T> tree, ref BinTreeThread<T> prevNode)        {            if (tree == null) return;            //中序遍历左子树,找到起始点            CreateByLDR(ref tree.left,ref prevNode);            //如果左指针域为空,左标志位放线索            tree.leftFlag = tree.left == null ? EnumNodeFlag.Thread : EnumNodeFlag.Child; //如果为空放线索,否则放孩子节点                        //如果右指针域为空,右标志位放线索            tree.rightFlag = tree.right == null ? EnumNodeFlag.Thread : EnumNodeFlag.Child;            if (prevNode != null)            {                //如果当前节点的左标志位为线索,则将前驱节点保存到当前节点的左指针域中                if (tree.leftFlag == EnumNodeFlag.Thread) tree.left = prevNode;                //如果前驱节点的右标志位为线索,则将当前节点保存到前驱节点的右指针域中                if (prevNode.rightFlag == EnumNodeFlag.Thread) prevNode.right = tree;            }            //保存前驱节点            prevNode = tree;            //遍历右子树进行同样的操作            CreateByLDR(ref tree.right,ref prevNode);        }        /// <summary>        /// 查找后继节点        /// </summary>        /// <typeparam name="T">二叉线索树类型</typeparam>        /// <param name="tree">当前节点</param>        /// <returns>后继节点</returns>        public static BinTreeThread<T> SearchNextNode<T>(BinTreeThread<T> tree)        {            if (tree == null) return null;            //没有右孩子,直接获取            if (tree.rightFlag == EnumNodeFlag.Thread) return tree.right;            //有右孩子,中序遍历查找右子树中序遍历的第一个节点(即为后继节点)            var rightNode = tree.right;            while (rightNode.leftFlag == EnumNodeFlag.Child)            {                rightNode = rightNode.left;            }            return rightNode;        }        /// <summary>        /// 查找前驱节点        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="tree">当前节点</param>        /// <returns>前驱节点</returns>        public static BinTreeThread<T> SearchPreNode<T>(BinTreeThread<T> tree)        {            if (tree == null) return null;            //没有左孩子,直接获取            if (tree.leftFlag == EnumNodeFlag.Thread) return tree.left;            //有左孩子,中序遍历左子树中往右链中第一个没有右孩子的节点即为前驱节点            var leftNode = tree.left;            while (leftNode.rightFlag == EnumNodeFlag.Child)            {                leftNode = leftNode.right;            }            return leftNode;        }        /// <summary>        /// 遍历线索二叉树(中序)        /// </summary>        /// <typeparam name="T">线索二叉树数据类型</typeparam>        /// <param name="tree">待操作线索二叉树</param>        public static void TraversalByLDR<T>(BinTreeThread<T> tree)        {            if (tree == null) return;            //查找起始结点(中序遍历的开始节点)            while (tree.leftFlag == EnumNodeFlag.Child)            {                tree = tree.left;            }            do            {                Console.Write(tree.data+"\t");                tree = SearchNextNode(tree); //利用线索获取后继节点            } while (tree != null);        }    }    /// <summary>    /// 线索二叉树存储结构    /// </summary>    /// <typeparam name="T">数据类型</typeparam>    public class BinTreeThread<T>    {        public T data; //数据        public BinTreeThread<T> left; //左指针域        public BinTreeThread<T> right; //右指针域        public EnumNodeFlag leftFlag; //左线索标志位        public EnumNodeFlag rightFlag; //右线索标志位    }    /// <summary>    /// 结点指针域指向的是孩子的指针还是线索的枚举    /// </summary>    public enum EnumNodeFlag    {        Child = 0, //指向孩子        Thread = 1 //指向前趋或后继的线索    }}

0 0
原创粉丝点击