一、定义:二叉树是n(n>=0)个节点的有限集合,该集合或者为空集或者有一公分根节点和两棵互不相交的、分别称为根节点的左子树和右子树的二叉树组成。
二、二叉树的特点:
1、每个节点最多有两棵子树,所以二叉树中不存在度大于二的 节点。
2、左子树和右子树的顺序不能颠倒。
3、即使树中的某个节点只有一棵子树,也要区分左右子树。
三、特殊二叉树:
1、斜树:所有节点都只有左子树的二叉树叫左斜树,所有节点都只有右子树的二叉树叫做右斜树。
2、满二叉树:在一棵二叉树中所有分支节点有存在左子树 和右子树,并且所有叶子节点都在同一层上,这样的二叉树称为满二叉树。
3、完全二叉树:对一棵具有n个节点的二叉树按层进行编号,如果编号为i(1<=i<=n)的节点与同样深度的满二叉树中编号为i的节点的位置完全相同,则这颗二叉树称为完全二叉树。完全二叉树具有以下特点:
- 叶子节点只能出现在最下两层
- 最下层的叶子一定集中在左部连续位置。
- 倒数第二层,若有叶子节点一定都在右部连续位置。
- 如果节点度为一,则该节点只有左孩子,即不存在只有右子树的情况。
- 同样节点的二叉树,完全二叉树的深度最小。
四、二叉树的性质:
1、在二叉树的第i层上最多只有2^(i-1)(i>=1)个节点。
2、深度为k的二叉树至多有2^k-1个节点(k>=1)。
3、对任何一棵二叉树T,如果其终端节点数为n0,度为2的节点为n2则n0=n2+1。
4、具有n个节点的完全二叉树的深度为log2n+1。
5、如果对一棵有n个节点的完全二叉树的节点按层序编号,对任意一节点有:
- 如果i=1,则节点i是二叉树的根,无双亲;如果i>1,则其双亲是节点i/2。
- 如2i>n,则节点无左孩子(节点为叶结点);否则其左孩子是节点2i。
- 如果2i+1>n,则节点i无右孩子;否则其右孩子是节点2i+1;
五、二叉树的存储结构
1、顺序存储:使用一维数组存储二叉树中的节点数组的下标能体现节点之间的逻辑结构。当存入数组的是完全二叉树时,相应的下标对应其相同的位置。每一个节点的双亲位置为其位置的1/2。对于一般的二叉树,可以将其按照完全二叉树编号,不存在的节点使用特殊的符号表示。这种表示方法的缺陷是对于不是完全二叉树的树来说使用顺序存储会浪费许多的存储空间。
2、二叉链表:树的每个节点都有一个数据域和两个指针域。
六、树的遍历:从二叉树的根节点出发按照某种顺序访问每个节点一次。
1、前序遍历:先访问根节点,然后先序遍历左子树在先序遍历右子树。
2、中序遍历:若树为空,则空操作返回,否则从根节点开始中序遍历左子树,然后访问根节点,最后中序遍历右子树。
3、后序遍历:若树为空,则空操作返回,否则从左到右先叶子后节点的方式遍历访问左右子树,最后访问根节点。
4、层序遍历:若树为空,则空操作返回,否则从树的第一层(树的根节点),开始访问,从上而下逐层遍历,在同一层中按照从左到右的顺序对节点逐个访问。
六、实现代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace 二叉树__链式结构
{
/// <summary>
/// 二叉链表的节点 字符
/// </summary>
class BitNode
{
/// <summary>
/// 数据域
/// </summary>
private char data;
/// <summary>
/// 指针域——左右孩子
/// </summary>
private BitNode lChild, rChild;
/// <summary>
/// 数据域与指针域的属性
/// </summary>
public char Data {
get { return data; }
set { data = value; }
}
public BitNode LChild {
get { return lChild; }
set { lChild = value; }
}
public BitNode RChild {
get { return rChild; }
set { rChild = value; }
}
/// <summary>
/// 节点的构造方法
/// </summary>
public BitNode()
{
data = default(char);
lChild = null;
rChild = null;
}
public BitNode (char e)
{
data = e;
lChild = null;
rChild = null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 二叉树__链式结构
{
/// <summary>
/// 二叉树的实现
/// </summary>
class BinaryTree
{
/// <summary>
/// 根节点
/// </summary>
private BitNode root;
/// <summary>
/// 根节点的只读属性
/// </summary>
public BitNode Root
{
get { return root; }
}
/// <summary>
/// 构造方法 给根节点赋值
/// </summary>
public BinaryTree ()
{
root = new BitNode();
}
public BinaryTree (char e)
{
root = new BitNode(e);
}
public BinaryTree (char[] datas,int i):this()
{
CreateBiTree(root,datas,i);
}
/// <summary>
/// 二叉树构建
/// 递归
/// </summary>
/// <param name="T"></param>
/// <param name="datas"></param>
public void CreateBiTree(BitNode node,char[] datas,int i)
{
if (node == null)
node = new BitNode();
if (i < datas.Length)
{
if (datas[i] == '#')
{
node = null;
}
else
{
node.Data = datas[i];
node.LChild = new BitNode();
CreateBiTree(node.LChild, datas, 2 * i + 1);
node.RChild = new BitNode();
CreateBiTree(node.RChild, datas, 2 * i + 2);
}
}
else node = null;
}
/// <summary>
/// 递归先序遍历
/// </summary>
/// <param name="node"></param>
public void PreOrderTraverse(BitNode node)
{
if (node == null)
return;
Console.Write(node.Data + " ");
PreOrderTraverse(node.LChild);
PreOrderTraverse(node.RChild);
}
/// <summary>
/// 递归中序遍历
/// </summary>
/// <param name="node"></param>
public void InOrderTraverse(BitNode node)
{
if (node == null)
return;
InOrderTraverse(node.LChild);
Console.Write(node.Data + " ");
InOrderTraverse(node.RChild);
}
/// <summary>
/// 递归后序遍历
/// </summary>
/// <param name="node"></param>
public void PostOrderTraverse(BitNode node)
{
if (node == null)
return;
PostOrderTraverse(node.LChild);
PostOrderTraverse(node.RChild);
Console.Write(node.Data + " ");
}
/// <summary>
/// 非递归中序遍历
/// </summary>
/// <param name="node"></param>
public void InOrderWithoutRecursion(BitNode node)
{
if (node == null)
return;
Stack<BitNode> nodes = new Stack<BitNode>();
BitNode p = node;
while (nodes.Count !=0|| p!=null)
{
//当p存在就将p入栈随后p指向p的左孩子
if(p!=null)
{
nodes.Push(p);
p = p.LChild;
}
//当p不存在时代表p的双亲结点没有左孩子或者左孩子已经输出过
//这时候输出双亲节点同时将p指向p的兄弟节点
else
{
p = nodes.Pop();
Console.Write(p.Data + " ");
p = p.RChild;
}
}
}
/// <summary>
/// 非递归前序遍历
/// </summary>
/// <param name="node"></param>
public void PreOrderWithoutRecursion(BitNode node)
{
if (node == null)
return;
Stack<BitNode> nodes = new Stack<BitNode>();
BitNode p = node;
char a;
while (nodes.Count !=0|| p!=null)
{
//p不为空就输出并且将p指向p的左孩子
if(p!=null)
{
a = p.Data;
Console.Write(p.Data + " ");
nodes.Push(p);
p = p.LChild;
}
//当p为空时代表p的双亲节点没有左孩子这时进入p的兄弟节点
else
{
p = nodes.Pop();
p = p.RChild;
}
}
}
/// <summary>
/// 非递归后序遍历
/// 当根节点的右孩子为空或者右孩子已经被访问过时访问根节点
/// </summary>
/// <param name="node"></param>
public void PostOrderWithoutRecursionv(BitNode node)
{
if (node == null)
return;
Stack<BitNode> nodes = new Stack<BitNode>();
BitNode p = node;
BitNode pLastVisit = new BitNode();
//将当前指针移到左子树的最下方
while (p!=null)
{
nodes.Push(p);
p = p.LChild;
}
while(nodes.Count !=0)
{
p = nodes.Pop();
//根节点的访问条件是右孩子为空或者右孩子被访问过
if(p.RChild !=null||p.RChild !=pLastVisit)
{
Console.Write(p.Data + " ");
pLastVisit = p;
}
else
{
nodes.Push(p);
//进入右子树
p = p.RChild;
//将当前指针移到右子树的最左边
while (p!=null)
{
nodes.Push(p);
p = p.LChild;
}
}
}
}
}
}