线索二叉树(C# 2.0)
线索二叉树主要是为了解决查找结点的线性前驱与后继不方便的难题。它只增加了两个标志性域,就可以充分利用没有左或右孩子的结点的左右孩子的存储空间来存放该结点的线性前驱结点与线性后继结点。两个标志性域所占用的空间是极少的,所有充分利用了二叉链表中空闲存的储空间。
using System;
using System.Collections.Generic;
using System.Text;
/*
作者:旋风
日期:2006-9-29
博客园主页:http://xuanfeng.cnblogs.com
内容:线索二叉树
*/
namespace LineNode
{
class Program
{
#region 二叉链表结点数据结构的定义
class LineNodes<T>
{
T data;
LineNodes<T> lNode, rNode;
int lTag, rTag;
public LineNodes(T data)
{
this.data = data;
}
public T Data
{
set
{
data = value;
}
get
{
return data;
}
}
public LineNodes<T> Lnode
{
set
{
lNode = value;
}
get
{
return lNode;
}
}
public LineNodes<T> Rnode
{
set
{
rNode = value;
}
get
{
return rNode;
}
}
public int Ltag
{
set
{
lTag = value;
}
get
{
return rTag;
}
}
public int Rtag
{
set
{
rTag = value;
}
get
{
return rTag;
}
}
}
#endregion
#region 构造一颗已知的线索二叉树
static LineNodes<string> GetLineTree()
{
LineNodes<string>[] lineNodes = new LineNodes<string>[9];
lineNodes[0] = new LineNodes<string>("A");
lineNodes[1] = new LineNodes<string>("B");
lineNodes[2] = new LineNodes<string>("C");
lineNodes[3] = new LineNodes<string>("D");
lineNodes[4] = new LineNodes<string>("E");
lineNodes[5] = new LineNodes<string>("F");
lineNodes[6] = new LineNodes<string>("G");
lineNodes[7] = new LineNodes<string>("H");
lineNodes[8] = new LineNodes<string>("I");
lineNodes[0].Lnode = lineNodes[1];
lineNodes[0].Rnode = lineNodes[2];
lineNodes[1].Lnode = lineNodes[3];
lineNodes[1].Rnode = lineNodes[4];
lineNodes[2].Lnode = lineNodes[5];
lineNodes[2].Rnode = lineNodes[6];
lineNodes[4].Lnode = lineNodes[7];
lineNodes[4].Rnode = lineNodes[8];
return lineNodes[0];
}
#endregion
#region 中序次序线索化算法
static LineNodes<string> preNode = null;//定义一个全局变量保存当前结点的前驱
static void MidOrder(LineNodes<string> headNode, LineNodes<string> postNode)
{
if (headNode != null)
{
MidOrder(headNode.Lnode, headNode);
Console.WriteLine(headNode.Data);
if (headNode.Lnode != null)
{
headNode.Ltag = 0;
}
else
{
headNode.Ltag = 1;
headNode.Lnode = preNode;
}
preNode = headNode;
MidOrder(headNode.Rnode, postNode);
if (headNode.Rnode != null)
{
headNode.Rtag = 0;
}
else
{
headNode.Rtag = 1;
headNode.Rnode = postNode;
}
}
}
#endregion
#region 在中根线索树上查找结点node的前驱结点
static LineNodes<string> GetPreNode(LineNodes<string> node)
{
LineNodes<string> preNode = null;
if (node != null)
{
if (node.Ltag == 1)
{
preNode = node.Lnode;
}
else
{
while (node.Rtag != 1)
{
node = node.Rnode;
}
preNode = node;
}
return preNode;
}
return null;
}
#endregion
#region 在中根线索树上查找结点node的后继结点
static LineNodes<string> GetPostNode(LineNodes<string> node)
{
LineNodes<string> postNode;
if (node != null)
{
if (node.Rtag == 1)
{
postNode = node.Rnode;
}
else
{
while (node.Lnode.Ltag != 1)
{
node = node.Lnode;
}
postNode = node;
}
return postNode;
}
return null;
}
#endregion
#region 测试的主办法
static void Main(string[] args)
{ //得到已知二叉树的根结点
LineNodes<string> headNode = GetLineTree();
//中序线索化已知二叉树
MidOrder(headNode, headNode);
//测试,查找结点I的前驱
Console.WriteLine("结点I的线性前驱结点是:");//正确应该是:E
Console.WriteLine(GetPreNode(headNode.Lnode.Rnode.Rnode).Data);
Console.WriteLine("结点F的线性后继结点是:");//正确应该是C
Console.WriteLine(GetPostNode(headNode.Rnode.Lnode).Data);
Console.Read();
}
#endregion
}
}
要实现线索二叉树,就必须定义二叉链表结点数据结构如下(定义请看代码):
Lnode |
Ltag |
Data |
Rtag |
Rnode |
说明:
1. Ltag=0时,表示Lnode指向该结点的左孩子;
2. Ltag=1时,表示Lnode指向该结点的线性前驱结点;
3. Rtag=0时,表示Rnode指向该结点的右孩子;
4. Rnode时,表示Rnode指向该结点的线性后继结点;
以二叉链表结点数据结构所构成的二叉链表作为二叉树的存储结构,叫做线索二叉链表;指向结点的线性前驱或者线性后继结点的指针叫做线索;加上线索的二叉树称为线索二叉树;对二叉树以某种次序遍历将其变为线索二叉树的过程叫做线索化。
中序次序线索化二叉树算法:
中序次序线索化是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访问结点时建立线索;(具体看代码)
检索中序二叉树某结点的线性前驱结点的算法:
1. 如果该结点的Ltag=1,那么Lnode就是它的线性前驱;
2. 如果该结点的Ltag=0,那么该结点左子树最右边的尾结点就是它的线性前驱点;
(具体请看代码)
检索中序二叉树某结点的线性后继结点和算法:
1. 如果该结点的Rtag=1,那么Rnode就是它的线性后继结点;
2. 如果该结眯的Rtag=0,那么该结点右子树最左边的尾结点就是它的线性后继结点
(具体请看代码)
解决方案中所有到二叉树的中序线索二叉树和中序线索链表的图
解决方案源码
using System;
using System.Collections.Generic;
using System.Text;
/*
作者:旋风
日期:2006-9-29
博客园主页:http://xuanfeng.cnblogs.com
内容:线索二叉树
*/
namespace LineNode
{
class Program
{
#region 二叉链表结点数据结构的定义
class LineNodes<T>
{
T data;
LineNodes<T> lNode, rNode;
int lTag, rTag;
public LineNodes(T data)
{
this.data = data;
}
public T Data
{
set
{
data = value;
}
get
{
return data;
}
}
public LineNodes<T> Lnode
{
set
{
lNode = value;
}
get
{
return lNode;
}
}
public LineNodes<T> Rnode
{
set
{
rNode = value;
}
get
{
return rNode;
}
}
public int Ltag
{
set
{
lTag = value;
}
get
{
return rTag;
}
}
public int Rtag
{
set
{
rTag = value;
}
get
{
return rTag;
}
}
}
#endregion
#region 构造一颗已知的线索二叉树
static LineNodes<string> GetLineTree()
{
LineNodes<string>[] lineNodes = new LineNodes<string>[9];
lineNodes[0] = new LineNodes<string>("A");
lineNodes[1] = new LineNodes<string>("B");
lineNodes[2] = new LineNodes<string>("C");
lineNodes[3] = new LineNodes<string>("D");
lineNodes[4] = new LineNodes<string>("E");
lineNodes[5] = new LineNodes<string>("F");
lineNodes[6] = new LineNodes<string>("G");
lineNodes[7] = new LineNodes<string>("H");
lineNodes[8] = new LineNodes<string>("I");
lineNodes[0].Lnode = lineNodes[1];
lineNodes[0].Rnode = lineNodes[2];
lineNodes[1].Lnode = lineNodes[3];
lineNodes[1].Rnode = lineNodes[4];
lineNodes[2].Lnode = lineNodes[5];
lineNodes[2].Rnode = lineNodes[6];
lineNodes[4].Lnode = lineNodes[7];
lineNodes[4].Rnode = lineNodes[8];
return lineNodes[0];
}
#endregion
#region 中序次序线索化算法
static LineNodes<string> preNode = null;//定义一个全局变量保存当前结点的前驱
static void MidOrder(LineNodes<string> headNode, LineNodes<string> postNode)
{
if (headNode != null)
{
MidOrder(headNode.Lnode, headNode);
Console.WriteLine(headNode.Data);
if (headNode.Lnode != null)
{
headNode.Ltag = 0;
}
else
{
headNode.Ltag = 1;
headNode.Lnode = preNode;
}
preNode = headNode;
MidOrder(headNode.Rnode, postNode);
if (headNode.Rnode != null)
{
headNode.Rtag = 0;
}
else
{
headNode.Rtag = 1;
headNode.Rnode = postNode;
}
}
}
#endregion
#region 在中根线索树上查找结点node的前驱结点
static LineNodes<string> GetPreNode(LineNodes<string> node)
{
LineNodes<string> preNode = null;
if (node != null)
{
if (node.Ltag == 1)
{
preNode = node.Lnode;
}
else
{
while (node.Rtag != 1)
{
node = node.Rnode;
}
preNode = node;
}
return preNode;
}
return null;
}
#endregion
#region 在中根线索树上查找结点node的后继结点
static LineNodes<string> GetPostNode(LineNodes<string> node)
{
LineNodes<string> postNode;
if (node != null)
{
if (node.Rtag == 1)
{
postNode = node.Rnode;
}
else
{
while (node.Lnode.Ltag != 1)
{
node = node.Lnode;
}
postNode = node;
}
return postNode;
}
return null;
}
#endregion
#region 测试的主办法
static void Main(string[] args)
{ //得到已知二叉树的根结点
LineNodes<string> headNode = GetLineTree();
//中序线索化已知二叉树
MidOrder(headNode, headNode);
//测试,查找结点I的前驱
Console.WriteLine("结点I的线性前驱结点是:");//正确应该是:E
Console.WriteLine(GetPreNode(headNode.Lnode.Rnode.Rnode).Data);
Console.WriteLine("结点F的线性后继结点是:");//正确应该是C
Console.WriteLine(GetPostNode(headNode.Rnode.Lnode).Data);
Console.Read();
}
#endregion
}
}