一,树的定义和基本术语
树是若干个结点组成的有限集合,其中必须有一个结点是根结点,其余结点划分为若干个互不相交的集合,每一个集合还是一棵树,称为根的子树。当树的结点个数为0时,我们称这棵树为空树,记为Φ。
关于树的基本术语;
结点:表示树中的元素,包括数据项和若干指向其子树的分支;
结点的度:结点所拥有的子树的个数;
叶子结点:度为0的结点叫做叶子结点,或者叫做终端结点;
分支结点:度不为0的结点,又叫做非终端结点;
孩子,兄弟,父亲(父节点);
路径,路径长度;
祖先,子孙;
结点的层数:规定根结点的层数为1,其余结点的层数=父节点层数+1;
树的深度:树中所有结点的最大层数;
树的度:树中各结点度的最大值叫做树的度;
森林:零颗或有限颗不相交的树的集合叫做森林;任何一棵树。删去根结点就变成了森林。
二,二叉树
二叉树(Binary Tree)是一种每个结点最多拥有2个子树的树结构,其中第1个子树被称为左子树,第2个子树被称为右子树。
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层上,这样的一棵二叉树称作满二叉树。
完全二叉树
完全二叉树是一种叶子结点只能出现在最下层和次下层且最下层的叶子结点集中在树的左边的特殊二叉树。
(1、完全二叉树中如果有度为1的结点,只可能有一个,且该结点只有左孩子。
2、深度为k的完全二叉树在k-1层上一定是满二叉树。)
二叉树的性质
性质1 :一棵非空在二叉树的第 i 层上至多有 2i -1个结点(i 1)。
性质2:一棵深度为k的二叉树中,最多具有2k-1个结点。
性质3:对于一棵非空的二叉树,如果叶子结点数为n0,度数为2的结点数为n2,则有: n0=n2+1。
性质4:具有n个结点的完全二叉树的深度k为 ⌊ log2n ⌋+1。
性质5:对于具有n个结点的完全二叉树,如果按照从上至下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号,则对于任意的序号为i的结点,有:
(1)如果i>1,则序号为i的结点的父结点的序号为 ⌊i/2⌋;如果i=1,则该结点是根结点,无父结点。
(2)如果2i≤n,则序号为i的结点的左子结点的序号为2i;如果2i>n,则序号为i的结点无左子结点。
(3)如果2i+1≤n,则序号为i的结点的右子结点的序号为2i+1;如果2i+1>n,则序号为i的结点无右子结点。
二叉树的存储结构
1.顺序存储结构
用一组连续的存储单元存放二叉树中的结点。一般是按照二叉树结点从上至下、从左到右的顺序存储。
2.链式存储结构
1)二叉链表存储
结点的存储结构为:
二叉树链式存储的每个结点可描述为:
class Node<T>
{
public Node<T> lChild; //左孩子
private T data; //数据域
public Node<T> rChild; //右孩子
public Node( ) {
data=null;
lChild=null;
rChild=null;
}
public Node(T x){
data=x;
lChild=null;
rChild=null; }
}
二叉链表的关键是确定二叉树的根,代码如下:
class BinaryTree<T>
{
public Node<T> root; //根结点
public BinaryTree() //创建一棵空二叉树
{
this.root = new Node<T>();
}
public BinaryTree(T x)
{
this.root = new Node<T>(x);
}
//……
}
二叉树的基本操作与实现
- 建立一棵空二叉树
public BinaryTree( )
{
this.root = new Node<T>();
}
- 生成一棵二叉树
public BinaryTree(T x)
{
this.root = new Node<T>(x);
}
- 二叉树中插入一个左孩子结点
public boolean insertLeft(T x, Node<T> parent)
{
if(parent==null) return false;
Node<T> p= new Node<T>(x);
if(parent.lChild==null)
parent.lChild = p;
else
{
p.lChild = parent.lChild;
parent.lChild = p;
}
return true;
}
- 删除二叉树的左子树
public boolean deleteLeft(Node<T> parent)
{
if(parent==null)
return false;
else
{
parent.lChild=null;
return true;
}
}
**
三,二叉树的遍历
按照某种顺序访问二叉树中的每个结点,使每个结点被访问一次且仅被访问一次。
- 先序遍历(DLR)二叉树的操作定义:
若二叉树为空,则空操作;否则
(1) 访问根结点;
(2) 先序遍历左子树;
(3) 先序遍历右子树。
public void preorder(Node<T> node)
{
if(node==null) return;
else
{
visit(node.getData()); //访问根结点
preOrder(node.lChild); //遍历左子树
preOrder(node.rChild); //遍历右子树
}
}
2.中序遍历(LDR)二叉树的操作定义:
若二叉树为空,则空操作;否则
(1) 中序遍历左子树;
(2) 访问根结点;
(3) 中序遍历右子树。
public void inorder(Node<T> node)
{
if(node==null) return;
else
{
inorder(node.lChild); //遍历左子树
visit(node.getData()); //访问根结点
inorder(node.rChild); //遍历右子树
}
}
3.后序遍历(LRD)二叉树的操作定义:
若二叉树为空,则空操作;否则
(1) 后序遍历左子树;
(2) 后序遍历右子树;
(3) 访问根结点。
public void postorder(Node<T> node)
{
if(node==null) return;
else
{
postorder(node.lChild); //遍历左子树
postorder(node.rChild); //遍历右子树
visit(node.getData()); //访问根结点
}
}