1.相关概念
- 节点的度 : 一个节点含有的子节点的个数叫做该节点的度 例如 上图 A节点的度为 6
- 叶节点或终端节点 : 度为0的节点叫叶节点 例如 B C H I … …
- 非终端节点或分支节点 : 度不为0的节点 例如 D E F G … …
- 父节点或双亲节点 : 若一个节点含有子节点 则该节点是其子节点的父节点 例如 : A是B的父节点
- 子节点 : 和父节点相反 一个节点有根节点 则 是该根节点的子节点 例如 B是A的子节点
- 兄弟节点 : 具有相同父节点的节点是兄弟节点 例如 B C是兄弟节点
- 树的度 : 一棵树 最大的节点的度是树的度 例如 : 上图度为 6
- 节点层次 : 从根开始定义 根为第一层 根的子节点为 2层 以此类推
- 树的高度或深度 : 树中节点最大层次 例如 上图深度是 4
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为堂兄弟节点
- 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
- 森林:由m(m>=0)棵互不相交的树的集合称为森林;
2.特点
- 每个节点做多2颗子树 及二叉树不存在度大于2的节点
- 二叉树的子树有左右之分 其子树的次序不能颠倒
3.完全二叉树和满二叉树的概念
- 满二叉树 : 一个二叉树 每一层节点都达到最大值 则这个二叉树就是满二叉树 就是说一个二叉树层数是 k 且节点总数为 (2^k) - 1 则他是满二叉树 <2^k表示 : 2的幂次方>
- 完全二叉树 : 对于深度是k 有n个节点的二叉树 当且仅当其每个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时 就是完全二叉树 满二叉树就是一种特殊的完全二叉树
4.二叉树的性质
- 二叉树第 i 层上最多有 2^(i-1) [ i>=1]
- 深度为k的二叉树至多有 2^k-1个节点(k>=1)
- 包含n个节点的二叉树高度至少为 log2 (n+1)=x --> 2^x=n+1
- 在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。
- 对于任意节点 其左子树的值都小于该节点的值 其右子树值都大于该节点的值
5.二叉树的存储方式
- 顺序结构
使用数组存储 一般使用数组只适合表示完全二叉树 因为不是完全二叉树会有空间浪费 在使用中只有堆会使用数组存储 二叉树顺序存储在物理上是数组 在逻辑上是二叉树
-
链式结构
用链表来表示二叉树 即用链来指示元素的逻辑关系 通常方法是链表里每个节点由三个域组成 数据域和左右指针域 左右指针域分别用来给出该节点左孩子和右孩子所在的链节点的存储地址
链式结构又分为二叉链和三叉链(红黑树)
-
二叉链 : 节点定义里包含左右两个后继
-
三叉链 : 在二叉链的基础加一个父亲前驱 这样给定任何节点都可以访问到其父亲
-
6.代码实现二叉树查询/添加/删除
package com.example.ioimage;
public class BSTree {
public static void main(String[] args) {
BSTree bsTree = new BSTree();
bsTree.put(16);
bsTree.put(14);
bsTree.put(35);
bsTree.put(12);
bsTree.put(15);
bsTree.put(25);
bsTree.put(40);
bsTree.put(10);
bsTree.put(20);
bsTree.put(27);
bsTree.put(38);
bsTree.put(41);
bsTree.put(26);
bsTree.put(30);
bsTree.put(39);
Node v1 = bsTree.query(30);
bsTree.delete(30);
Node v2 = bsTree.query(30);
}
private Node tree;//指向根节点
//删除操作
public void delete(int value) {
Node node = tree;//记录要删除的节点
Node parent = null;//记录要删除节点的父节点
// 查询到要删除的元素及其父元素
while (node != null){
if (node.value > value){//当该节点值大于value时 说明该元素在左子树上
parent = node;//当前节点就是父节点
node = node.left;//要删除的节点就是父节点的子节点
}else if (node.value < value){
parent = node;
node = parent.right;
}else {
break;
}
}
if (node == null){
return;
}
//当要删除的节点有2个子节点 此时需要拿到右子树所有节点的最小节点替换当前节点 然后删除右子树的最小节点
if (node.left != null && node.right != null){
//记录右子树的最小节点
Node rightTree = node.right;
//记录右子树最小节点的父节点
Node rightTree_parent = node;
//查询节点值
while (rightTree.left != null){//右子树的最小节点是最左侧的叶节点
rightTree_parent = rightTree;
rightTree = rightTree.left;
}
//用右子树的最小节点替换当前要删除的节点
node.value = rightTree.value;
//删除右子树最小节点
node = rightTree;
parent = rightTree_parent;
}
//当要删除的节点有1个子节点 则删除该节点 把删除节点的父节点指向删除节点的子节点
Node child = null;//定义子节点
if (node.left != null){
child = node.left;
}else if (node.right != null){
child = node.right;
}else {
child = null;
}
//执行删除操作
if (parent == null){//如果父节点为空 说明要删除根节点
tree = child;
}else if (parent.left == node){//更新父节点的左指针
parent.left = child;
}else {//否则更新右指针
parent.right = child;
}
}
//添加操作
public boolean put(int value) {
if (tree == null) {//父节点为空 则创建节点
tree = createNode(value);
return true;
}
Node parent = tree;//记录父节点
while (parent != null) {
if (parent.value > value) {//当父节点值大于当前值 则存储左子树上
if (parent.left == null) {
parent.left = createNode(value);//创建节点并把父节点指向该节点
return true;
}
parent = parent.left;//令父节点等于做子树 方便下一次插入
}
if (parent.value < value) {//当父节点值小于当前值 则存储右子树上
if (parent.right == null) {
parent.right = createNode(value);
return true;
}
parent = parent.right;
}
}
return false;
}
//查询操作
public Node query(int value) {
Node parent = tree;
while (parent != null) {
if (parent.value > value) {//当前值小于父节点值 则去左子树查询
parent = parent.left;
} else if (parent.value < value) {//当前值大于于父节点值 则去右子树查询
parent = parent.right;
} else {//否则返回父节点
return parent;
}
}
return parent;
}
//创建节点
private Node createNode(Node left, int value, Node right) {
return new Node(value, left, right);
}
private Node createNode(int value) {
return createNode(null, value, null);
}
//定义一个节点内部类
private static class Node {
private int value;
private Node left;
private Node right;
public Node(int value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
}
}