树的基本概念与术语
树的定义:
- 树是N(N>=0)个结点组成的有穷集合T
树的特征:
- 除N=0的树外,有且仅有一个特定的称为根的结点
- 其余结点分为
m(m>=0)
个互不相交的有穷集合,其中每个集合都是一棵树,称为该根的子树
树的特点:
- 有一个总根
- 没有分支相交
- 树有层次
基本术语:
- 结点的度:该结点具有子树的数目
- 叶子结点:度为0的结点
- 树的度:树中结点度的最大值
- 结点的层:根到该结点的路径长度(根为第0层)
- 树的高度:树中结点层的最大值
- 子女与双亲:子女指该结点子树的根节点,双亲即该结点
- 兄弟与堂兄弟:同一双亲孩子之间称为兄弟,其双亲在同一层的结点互为堂兄弟
- 祖先与子孙:从根到该结点所经分支上的所有结点称为该结点的祖先,以该结点为根的子树中的所有结点称为该结点的子孙
- 森林:m棵互不相交的树的集合
二叉树
二叉树的定义及性质:
- 二叉树是结点的有穷集合,二叉树可以是空树或者由一个根结点和其左右子树构成,且其左右子树满足二叉树的定义
- 二叉树的基本形态
二叉树的特征:
- 二叉树的每个结点的度不大于
2
- 二叉树的子树有左右之分
二叉树的性质
- 二叉树中层数为
i
的结点至多有2^i
个 - 高度为
k
的二叉树至多有2^(k+1)-1
个结点,这样的二叉树称为满二叉树 - 若一棵具有
n
个结点,高度为k
的二叉树,其中所有结点与高度为k
的满二叉树中编号由1至n的结点对应,这样的二叉树称为完全二叉树
满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树
- 设二叉树中叶子结点的个数为
n0
,度为1结点的个数为n1
,度为2结点的个数为n2
,则n0=n2+1
(推导:通过结点个数得出n0+n1+n2=n
,通过结点和边的关系n1+2n2=n-1
) - 将一棵具有
n
个结点的完全二叉树按层次顺序(从上到下,从左到右)从1
开始编号,则对编号为i
的结点有:
若i不为1,则编号为i结点的双亲结点编号为[i/2]
若2i<=n,则编号为i结点的左孩子的编号为2i,否则i无左孩子
若2i+1<=n,则编号为i结点的右孩子的编号为2i+1,否则i无有孩子
具有n个结点的完全二叉树高度为
利用n大于2^k-1小于等于2^(k+1)-1处理后两边同时取对数再取整得到完全二叉树的高度
二叉树结点的结构
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace ConsoleApp1
{
public class BinTreeNode<T> : IComparable<BinTreeNode<T>> where T : IComparable<T>
{
private T _data;
private BinTreeNode<T> _leftChild;
private BinTreeNode<T> _rightChild;
public T Data
{
get { return _data; }
set
{
if (value == null)
throw new ArgumentNullException();
_data = value;
}
}
public BinTreeNode<T> LeftChild
{
get { return _leftChild; }
set { _leftChild = value; }
}
public BinTreeNode<T> RightChild
{
get { return _rightChild; }
set { _rightChild = value; }
}
public BinTreeNode(T data)
{
if (data == null)
throw new ArgumentNullException();
_data = data;
_leftChild = null;
_rightChild = null;
}
public BinTreeNode(T data, BinTreeNode<T> left, BinTreeNode<T> right)
{
if (data == null)
throw new ArgumentNullException();
_data = data;
_leftChild = left;
_rightChild = right;
}
public int CompareTo(BinTreeNode<T> other)
{
if (other == null)
throw new ArgumentNullException();
return _data.CompareTo(other._data);
}
二叉树的遍历
定义
- 按照一定次序访问树中所有结点,并且每个结点的值仅被访问一次的过程
遍历的方式
- 前序遍历:访问根结点,前序遍历左子树,前序遍历右子树
- 中序遍历:中序遍历左子树,访问根节点,中序遍历右子树
- 后序遍历:后序遍历左子树,后序遍历右子树,访问根节点
- 层序遍历:遍历第0层、遍历第1层、…、遍历第k层(k为树的高度)
二叉树的实现
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp1
{
public class BinTree<T>where T:IComparable<T>
{
private BinTreeNode<T> _root;
private string _orderString;
public BinTreeNode<T> Root
{
get { return _root; }
set { _root = value; }
}
public BinTree(BinTreeNode<T> root)
{
_root = root;
}
public void Insert(BinTreeNode<T> current, BinTreeNode<T> lChild, BinTreeNode<T> rChild)
{
if (current == null)
throw new ArgumentNullException();
current.LeftChild = lChild;
current.RightChild = rChild;
}
public string PreOrderTraversal()
{
_orderString = string.Empty;
PreOrder(_root);
return _orderString.Trim();
}
private void PreOrder(BinTreeNode<T>current)
{
if (current == null)
return;
_orderString += current.Data + " ";
PreOrder(current.LeftChild);
PreOrder(current.RightChild);
}
public string MidOrderTraversal()
{
_orderString = string.Empty;
MidOrder(_root);
return _orderString.Trim();
}
private void MidOrder(BinTreeNode<T>current)
{
if (current == null)
return;
MidOrder(current.LeftChild);
_orderString += current.Data + " ";
MidOrder(current.RightChild);
}
public string PostOrderTraversal()
{
_orderString = string.Empty;
PostOrder(_root);
return _orderString.Trim();
}
private void PostOrder(BinTreeNode<T>current)
{
if (current == null)
return;
PostOrder(current.LeftChild);
PostOrder(current.RightChild);
_orderString += current.Data + " ";
}
public string LevelTraversal()
{
if (Root == null)
return string.Empty;
_orderString = string.Empty;
LinkQueue<BinTreeNode<T>> lq = new LinkQueue<BinTreeNode<T>>();
lq.EnQueue(_root);
while (lq.IsEmpty() == false)
{
BinTreeNode<T> current = lq.QueueFront;
lq.DeQueue();
_orderString += current.Data.ToString() + " ";
if (current.LeftChild != null)
lq.EnQueue(current.LeftChild);
if (current.RightChild != null)
lq.EnQueue(current.RightChild);
}
return _orderString.Trim();
}
private BinTreeNode<T> FindParent(BinTreeNode<T> current, BinTreeNode<T> find)
{
if (find == null)
throw new ArgumentNullException();
if (current == null)
return null;
if (current != null && current.LeftChild == find)
return current;
if (current != null && current.RightChild == find)
return current;
BinTreeNode<T> temp = FindParent(current.LeftChild, find);
if (temp != null)
return temp;
return FindParent(current.RightChild, find);
}
public BinTreeNode<T> GetParent(BinTreeNode<T> find)
{
if (find == null)
throw new ArgumentNullException();
return FindParent(_root, find);
}
public BinTreeNode<T> GetLeftSibling(BinTreeNode<T> current)
{
if (current == null)
throw new ArgumentNullException();
BinTreeNode<T> parent = GetParent(current);
if (parent != null && parent.LeftChild != null && parent.LeftChild.Equals(current) == false)
return parent.LeftChild;
return null;
}
public BinTreeNode<T> GetRightSibling(BinTreeNode<T> current)
{
if (current == null)
throw new ArgumentNullException();
BinTreeNode<T> parent = GetParent(current);
if (parent != null && parent.RightChild != null && parent.RightChild.Equals(current) == false)
return parent.RightChild;
return null;
}
public void DeleteSubTree(BinTreeNode<T> current)
{
if (current == null)
throw new ArgumentNullException();
if (_root != null && _root.Equals(current))
{
_root = null;
return;
}
BinTreeNode<T> parent = GetParent(current);
if (parent != null && parent.LeftChild != null && parent.LeftChild.Equals(current))
parent.LeftChild = null;
if (parent != null && parent.RightChild != null && parent.RightChild.Equals(current))
parent.RightChild = null;
}
public BinTreeNode<T> Search(T data)
{
if (data == null)
throw new ArgumentNullException();
return FindDate(_root, data);
}
public BinTreeNode<T> FindDate(BinTreeNode<T> current, T data)
{
if (data == null)
throw new ArgumentNullException();
if (current == null)
return null;
if (current.Data.CompareTo(data) == 0)
return current;
BinTreeNode<T> temp = FindDate(current.LeftChild, data);
if (temp != null)
return temp;
return FindDate(current.RightChild, data);
}
public void Exchange()
{
Exchange(_root);
}
private void Exchange(BinTreeNode<T> current)
{
if (current == null)
throw new ArgumentNullException();
if (current.LeftChild != null || current.RightChild != null)
{
BinTreeNode<T> temp = current.LeftChild;
current.LeftChild = current.RightChild;
current.RightChild = temp;
}
if (current.LeftChild != null) Exchange(current.LeftChild);
if (current.RightChild != null) Exchange(current.RightChild);
}
public int GetLeafCount()
{
int count = 0;
FindLeafCount(_root, ref count);
return count;
}
private void FindLeafCount(BinTreeNode<T> current, ref int count)
{
if (current == null)
return;
if (current.LeftChild == null && current.RightChild == null)
count++;
FindLeafCount(current.LeftChild, ref count);
FindLeafCount(current.RightChild, ref count);
}
}
}
//
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
BinTreeNode<string> A = new BinTreeNode<string>("A");
BinTreeNode<string> B = new BinTreeNode<string>("B");
BinTreeNode<string> C = new BinTreeNode<string>("C");
BinTreeNode<string> D = new BinTreeNode<string>("D");
BinTreeNode<string> E = new BinTreeNode<string>("E");
BinTreeNode<string> F = new BinTreeNode<string>("F");
BinTree<string> binTree = new BinTree<string>(A);
binTree.Insert(A, B, E);
binTree.Insert(B, null, C);
binTree.Insert(E, null, F);
binTree.Insert(C, D, null);//构造一棵树,用来实现各种方法
}
}
}
二叉树的存储
顺序存储
- 完全二叉树利用顺序存储(数组)
- 非完全二叉树利用链式存储