树与二叉树
1. 树
表明一种上下级的关系 ,是n(n>=0)个节点的有限集
1)空树:n=0,不包含任何结点
2)非空树:n>0,此时有且仅有一个“根结点”
n>1,此时其余节点可分为(m>0)个互不相交的有限集
1.1 基本的概念
结点的度:结点拥有的子树的个数
叶子结点:度为0的结点称为叶子结点或终端结点
树的度:各个结点度的最大值
树的深度/高度: 树中结点的最大层次数称为树的深度或高度
父亲、儿子、兄弟
父亲:一个结点的直接前驱结点
儿子:一个结点的直接后继结点
兄弟:同一个父亲结点的其他结点
祖先、子孙、堂兄弟
节点的祖先:从根节点到该结点路径上的所有结点
子孙:以某结点为根的树中的任一结点都称为该结点的子孙
有序树、无序树、m叉树
有序树:将树中结点的各子树看成是从左至右是有次序的,子树间不能互换位置,则称该树为有序树。
无序树:以上概念否则为无序树。
m叉树:树中所有结点最大度数为m的有序树称为m叉树
森林:是m棵互不相交的树的集合,对树中每个结点而言,其子树的集合即为森林。
###1.2 树的表示
1.3 树的应用
1,目录结构
2, 单位组织架构
2.二叉树
2.1 概念
每个结点的度均不超过2的有序树,称为二叉树。
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成。
2.2 二叉树的特点
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,其子树的次序不能颠倒。
- 对于任何一棵二叉树,如果其终端结点数比树中度为2的结点数多一个。
- 二叉树的第i层上,最多有2^(i-1)个结点。
2.3 现实中的二叉树
2.4 特殊二叉树
满二叉树一定是完全二叉树,而完全二叉树不一定是满二叉树。
2.4.1 满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是 说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
2.4.2 完全二叉树(堆)
若在一棵二叉树中,在最下层从最右侧起去掉相邻的若干叶子结点,得到的二叉树称为完全二叉树。
完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。 要注意的是满二叉树是一种特殊的完全二叉树。
对于一棵有n个结点的完全二叉树的结点进行编号,对于任一结点有:
1,如果i=1,则结点i为二叉树的根结点,无双亲
i>1,则其双亲结点PARENT(i)是结点[i/2];
2,如果2i>n,则结点i无左孩子;否则其左孩子是结点2i;
3,如果2i+1>n,则结点i无右孩子,否则其有孩子的结点2i+1;
2.5 二叉树的存储结构
在物理上是一个数组,在逻辑上是一颗二叉树
2.5.1 顺序存储
数组:适用于完全二叉树/满二叉树。对于不是完全二叉树,无法确定结点之间的前驱后继关系,会造成空间浪费。
[外链图片转存失败(img-deHgmlmW-1564736814704)(E:\javaclass\顺序二叉树.png)]
2.5.2 链式存储
[外链图片转存失败(img-axZElskC-1564736814706)(E:\javaclass\二叉链表.png)]
为了方便找到父节点,再加一个域来储存父结点信息 称为三叉链表
[外链图片转存失败(img-oesuPLIZ-1564736814706)(E:\javaclass\三叉链表.png)]
2.6 二叉树的实现
//定义二叉树结点类
class BinaryTreeBode{//二叉链表
Object Date;
Node left;
Node right;
}
class BinaryTreeNode{//三叉链表
Object value;
Node left;
Node right;
Node parent;
}
2.6.1 二叉树的遍历算法
先序遍历DLR:(根 左子树 右子树)对于结点处理工作是在它的诸儿子结点被处理之前进行的
/**
* 二叉树的前序遍历 递归算法
*/
@Override
public void preOrderTraverse() {
System.out.print("二叉树的前序遍历:");
this.preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(BinaryNode root){
if(root!=null){
System.out.print(root.value+" ");
preOrderTraverse(root.left);
preOrderTraverse(root.right);
}
}
中序遍历LDR:(左子树 根 右子树)对于结点处理工作是在它的左子树被处理之后
/**
* 二叉树的中序遍历 递归算法
*/
@Override
public void inOrderTraverse() {
System.out.print("二叉树的中序遍历:");
this.inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(BinaryNode root){
if(root!=null){
inOrderTraverse(root.left);
System.out.print(root.value+" ");
inOrderTraverse(root.right);
}
}
/**
* 非递归式中序遍历 借助栈
*/
@Override
public void inOrderByStack() {
System.out.print ("中序非递归遍历:");
Deque<BinaryNode> stack = new LinkedList<BinaryNode>();
BinaryNode current = root;
while (current!=null || !stack.isEmpty()){
while (current!=null){
stack.push(current);
current = current.left;
}
if(!stack.isEmpty()){
current=stack.pop();
System.out.print(current.value+" ");
current =current.right;
}
}
}
后序遍历LRD:(左子树 右子树 根)对于结点处理工作是在它的诸儿子结点被处理之后进行的
/**
* 二叉树的后序遍历
*/
@Override
public void postOrderTraverse() {
System.out.print("二叉树的后续遍历:");
this.postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(BinaryNode root){
if(root!=null){
this.postOrderTraverse(root.left);
this.postOrderTraverse(root.right);
System.out.print(root.value+" ");
}
}
二叉树按层次遍历
/**
* 按照层次进行遍历 借助队列
*/
@Override
public void levelOrderByStack() {
if(root!=null){
System.out.print("二叉树按层次遍历:");
//新建队列
Queue<BinaryNode> queue = new LinkedList<BinaryNode>();
((LinkedList<BinaryNode>) queue).add(root);
while (queue.size()!=0){
int len =queue.size();
for(int i=0;i<len;i++){
BinaryNode temp = queue.poll();
System.out.print(temp.value+" ");
if (temp.left!=null){
((LinkedList<BinaryNode>) queue).add(temp.left);
}
if(temp.right!=null){
((LinkedList<BinaryNode>) queue).add(temp.right);
}
}
}
System.out.println();
}else {
System.out.println("二叉树为空");
}
}
}
2.6.2 二叉树的高度
/**
*二叉树的高度
* @return
*/
@Override
public int getHeight() {
System.out.print("二叉树的高度为: ");
return getHeight(root);
}
private int getHeight(BinaryNode root){
if(root!=null){
int LHeight = this.getHeight(root.left);
int RHeight = this.getHeight(root.right);
return (LHeight>RHeight ? LHeight+1:RHeight+1);
}else {
return 0;
}
}
2.6.3 二叉树的结点个数
/**
* 获取二叉树的结点个数
* @return
*/
@Override
public int size() {
System.out.print("二叉树的结点个数为:");
return this.size(root);
}
private int size(BinaryNode root){
if(root!=null){
int lSize = this.size(root.left);
int rSize = this.size(root.right);
return lSize+rSize+1;
}else {
return 0;
}
}
2.6.4 在二叉树中找指定的某一值
/**
* 在二叉树中查找某一指定值
* @param value
* @return
*/
@Override
public BinaryNode findKey(Object value) {
return findKey(value,root);
}
private BinaryNode findKey(Object value,BinaryNode root){
if (root==null){
return null;
}else if(root!=null && root.value==value){
return root;
}else {
BinaryNode node1 = this.findKey(value,root.left);
BinaryNode node2 = this.findKey(value,root.right);
if(node1!=null&& node1.value==value){
return node1;
}else if(node2!=null && node2.value==value){
return node2;
}else {
return null;
}
}
}