二叉链表存储结构
使用二叉链表存储二叉树,声明结点类:
public class Node<T>
{
//声明字段:数据域、左孩子、右孩子;
public T data;
public Node<T> lChild;
public Node<T> rChild;
//声明属性:
public T Data { get => data; set => data = value; }
public Node<T> LChild { get => lChild; set => lChild = value; }
public Node<T> RChild { get => rChild; set => rChild = value; }
//重载构造函数:
public Node(T data)
{
this.data = data;
}
public Node(T data, Node<T> lChild, Node<T> rChild)
{
this.data = data;
this.lChild = lChild;
this.rChild = rChild;
}
public Node()
{
this.data = default;
this.lChild = null;
this.rChild = null;
}
}
声明二叉树类,同时声明层次遍历方法,在LinkBiTree类中,我使用了preOrderList、midOrderList以及postOrderList三个列表类型字段来存储遍历得到的结果。
//声明类:二叉树
public class LinkBiTree<T>
{
//声明字段:根节点;
public Node<T> head;
//声明属性:
public Node<T> Head { get { return head; } set { head = value; } }
//重载构造函数:
public LinkBiTree(T data)
{
Node<T> p = new Node<T>(data);
head = p;
}
public LinkBiTree()
{
head = null;
}
//声明方法:判断是否为空
public bool IsEmpty()
{
return head == null;
}
//声明字段:用于存储遍历列表
public List<T> preOrderList = new List<T>();
public List<T> midOrderList = new List<T>();
public List<T> postOrderList = new List<T>();
}
递归算法实现二叉树遍历
先根遍历
先根遍历的原理就是先访问根结点,然后分别先序遍历左子树、右子树。即对于每一个结点来说,都需要不断往下搜索,直到搜索到null空结点为止。在搜索过程中的每一个结点都遵循根、左、右的遍历顺序,代码实现如下:
//LinkBiTree
public void PreOrder(Node<T> root)
{
if (IsEmpty())
{
Console.WriteLine("Tree is empty!!");
}
if (root != null)
{
preOrderList.Add(root.data);//将结果保存在列表中;
PreOrder(root.LChild);
PreOrder(root.rChild);
}
}
中根遍历
同理,可以通过左、根、右的顺序实现中根遍历的递归算法。代码实现如下:
//LinkBiTree
//声明方法:使用递归进行中序遍历
public void MidOrder(Node<T> root)
{
if (IsEmpty())
{
Console.WriteLine("Tree is empty!!");
}
if (root != null)
{
//在这里体现左、根、右的遍历顺序:
MidOrder(root.LChild);
midOrderList.Add(root.data);//将结果保存在列表中;
MidOrder(root.rChild);
}
}
后根遍历
//LinkBiTree
//声明方法:使用递归进行后序遍历
public void PostOrder(Node<T> root)
{
if (IsEmpty())
{
Console.WriteLine("Tree is empty!!");
}
if (root != null)
{
//在这里体现根、左、右的遍历顺序:
PostOrder(root.LChild);
PostOrder(root.rChild);
postOrderList.Add(root.data);//将结果保存在列表中;
}
}
先序建立二叉树
建立二叉树可以通过先序、中序、后序遍历得到的序列进行还原,但前提是所有的叶子必须是#,即表示该处为空结点。建立二叉树的过程同样通过递归实现,输入形参root作为该二叉树的根节点,建立二叉链表。
在该方法中,我使用队列preQueue存储输入的遍历序列,每次DeQueue()得到数据字段temp,建立起左子树、右子树,并实现递归,以temp.equals(“#”)作为出口。(中序、后序的原理与此相同)代码演示如下:
//LinkBiTree
//声明方法:先序建立二叉树
public void PreCreateTree(ref Node<T> root)
{
T temp = preQueue.Dequeue();
if (temp.Equals("#"))
{
root = null;
}
else
{
root = new Node<T>(temp);
PreCreateTree(ref root.lChild);
PreCreateTree(ref root.rChild);
}
return;
}
判断二叉树是否为对称二叉树
对称二叉树的判断,可以基于左右子树的深度进行判断。所以我声明了TreeDepth()方法,能够从root出发,通过想左子树和右子树分别遍历,得到各个结点的最大深度,即为该树的深度。在此基础上,我使用IsBalanceTree()方法判断二叉树是否为对称二叉树。在当中我使用了字段dis,用于存储该节点左右子树的深度之差,如果为0,则进一步判断,实现递归。
//LinkBiTree
//声明方法:求树的深度
public int TreeDepth(Node<T> root)
{
if (root == null)
{
return 0;
}
else
{
int left_depth = TreeDepth(root.LChild);
int right_depth = TreeDepth(root.rChild);
if (left_depth > right_depth)
{
return left_depth + 1;
}
else
{
return right_depth + 1;
}
}
}
//重载方法:
public int TreeDepth()
{
return TreeDepth(head);
}
public Queue<T> preQueue = new Queue<T>();
//声明方法:判断一棵树是否是对称二叉树:
public bool IsBalanceTree(Node<T> root)
{
if (root == null)
{
return true;
}
//创建字段dis,存储左右子树的深度差:
int dis = TreeDepth(root.lChild) - TreeDepth(root.rChild);
//进入判断,递归运算:
if (dis != 0)
{
return false;
}
else
{
return IsBalanceTree(root.rChild) && IsBalanceTree(root.lChild);
}
}
//重载方法:
public bool IsBalanceTree()
{
return IsBalanceTree(head);
}
本文的方法均遵循递归的思路实现,这也是基于二叉链表这一存储方式和二叉树这一结构的特殊性。欢迎批评指正,有任何问题都可以私信我!