二叉树(链表实现)
1.1 树的基本定义
树是我们计算机中非常重要的一种数据结构,同时使用树这种数据结构,可以描述现实生活中的很多事物,例如家谱、单位的组织架构、等等。
树是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
树具有以下特点:
- 每个结点有零个或多个子结点;
- 没有父结点的结点为根结点;
- 每一个非根结点只有一个父结点;
- 每个结点及其后代结点整体上可以看做是一棵树,称为当前结点的父结点的一个子树;
1.2 树的相关术语
结点的度:
一个结点含有的子树的个数称为该结点的度;
叶结点:
度为0的结点称为叶结点,也可以叫做终端结点
分支结点:
度不为0的结点称为分支结点,也可以叫做非终端结点
结点的层次:
从根结点开始,根结点的层次为1,根的直接后继层次为2,以此类推
结点的层序编号:
将树中的结点,按照从上层到下层,同层从左到右的次序排成一个线性序列,把他们编成连续的自然数。
树的度:
树中所有结点的度的最大值
树的高度(深度):
树中结点的最大层次
森林:
m(m>=0)个互不相交的树的集合,将一颗非空树的根结点删去,树就变成一个森林;给森林增加一个统一的根结点,森林就变成一棵树
孩子结点:
一个结点的直接后继结点称为该结点的孩子结点
双亲结点(父结点):
一个结点的直接前驱称为该结点的双亲结点
兄弟结点:
同一双亲结点的孩子结点间互称兄弟结点
1.3 二叉树的基本定义
二叉树就是度不超过2的树(每个结点最多有两个子结点)
满二叉树:
一个二叉树,如果每一个层的结点树都达到最大值,则这个二叉树就是满二叉树。
描述 | 公式 |
---|---|
每一层结点的个数 | k为层数 |
完全二叉树:
叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
1.4 二叉查找树的创建
结点类API设计:
类名 | Node<Key,Value> |
---|---|
构造方法 | Node(Key key, Value value, Node left, Node right):创建Node对象 |
成员变量 | 1.public Node left:记录左子结点 2.public Node right:记录右子结点 3.public Key key:存储键 4.public Value value:存储值 |
二叉查找树API设计:
类名 | BinaryTree<Key extends Comparable,Value> |
---|---|
构造方法 | BinaryTree():创建BinaryTree对象 |
成员变量 | 1.private Node root:记录根结点 2.private int N:记录树中元素的个数 |
成员方法 | 1. public void put(Key key,Value value):向树中插入一个键值对 2.private Node put(Node x, Key key, Value val):给指定树x上,添加一个键值对,并返回添加后的新树 3.public Value get(Key key):根据key,从树中找出对应的值 4.private Value get(Node x, Key key):从指定的树x中,找出key对应的值 5.public void delete(Key key):根据key,删除树中对应的键值对 6.private Node delete(Node x, Key key):删除指定树x上的键为key的键值对,并返回删除后的新树 7.public int size():获取树中元素的个数 8.public Key min():找出树中最小的键 9.private Node min(Node x):找出指定树x中,最小键所在的结点 10.public Key max():找出树中最大的键 11.public Node max(Node x):找出指定树x中,最大键所在的结点 |
二叉查找树实现
插入方法put实现思想:
1.如果当前树中没有任何一个结点,则直接把新结点当做根结点使用
2.如果当前树不为空,则从根结点开始:
2.1如果新结点的key小于当前结点的key,则继续找当前结点的左子结点;
2.2如果新结点的key大于当前结点的key,则继续找当前结点的右子结点;
2.3如果新结点的key等于当前结点的key,则树中已经存在这样的结点,替换该结点的value值即可。
查询方法get实现思想:
从根节点开始:
1.如果要查询的key小于当前结点的key,则继续找当前结点的左子结点;
2.如果要查询的key大于当前结点的key,则继续找当前结点的右子结点;
3.如果要查询的key等于当前结点的key,则树中返回当前结点的value。
删除方法delete实现思想:
1.找到被删除结点;
2.找到被删除结点右子树中的最小结点minNode
3.删除右子树中的最小结点
4.让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
5.让被删除结点的父节点指向最小结点minNode
代码:
/**
* 二叉树
*/
public class BinaryTree<Key extends Comparable<Key>, Value> {
// 记录根结点
private Node root;
// 记录树中元素的个数
private int N;
public BinaryTree() {
}
// 获取树中的元素个数
public int size() {
return N;
}
// 向树中添加元素key-value
public void put(Key key, Value value) {
root = put(root, key, value);
}
// 向指定的树x中添加key-value,并返回添加元素后新的树
private Node put(Node x, Key key, Value value) {
// 如果x结点为空,则直接创建新结点存储数据并返回
if (x == null) {
// 元素个数+1
N++;
return new Node(key, value, null, null);
}
// 如果x结点不为空,则将x.key与传入的key进行比较,寻找插入点
// 如果(key>x.key),则继续寻找当前结点的右子结点
if (key.compareTo(x.key) > 0) {
x.right = put(x.right, key, value);
}
// 如果(key<x.key),则继续寻找当前结点的左子结点
if (key.compareTo(x.key) < 0) {
x.left = put(x.left, key, value);
}
// 如果(key=x.key),则替换当前结点的value值
if (key.compareTo(x.key) == 0) {
x.value = value;
}
return x;
}
// 查询树中指定key对应的value
public Value get(Key key) {
return get(root, key);
}
// 从指定的树x中,查找key对应的值
private Value get(Node x, Key key) {
// x树为null
if (x == null)
return null;
// x树不为null
// 如果(key<x.key),递归查询当前结点的左子树
if (key.compareTo(x.key) < 0) {
return get(x.left, key);
}
// 如果(key>x.key),递归查询当前结点的右子树
if (key.compareTo(x.key) > 0) {
return get(x.right, key);
}
// 如果(key=x.key),返回当前结点的value值
if (key.compareTo(x.key) == 0) {
return x.value;
}
return null;
}
// 删除树中key对应的value
public void delete(Key key) {
delete(root, key);
}
// 删除指定树x中的key对应的value,并返回删除后的新树
private Node delete(Node x, Key key) {
// 如果x结点为空,直接返回空置
if (x == null) {
return null;
}
// 如果x结点不为空,则比较key值,找到要删除的结点
// 如果(key>x.key),查找当前结点的右子树
if (key.compareTo(x.key) > 0) {
x.right = delete(x.right, key);
}
// 如果(key<x.key),查找当前结点的左子树
if (key.compareTo(x.key) < 0) {
x.left = delete(x.left, key);
}
// 如果(key=x.key),找到要删除的结点,进行删除
if (key.compareTo(x.key) == 0) {
// 要找到x结点的右子树中最小的结点,替换x结点
// 如果x结点的右子树为空,则直接返回x的左子树
if (x.right == null) {
// 元素个数-1
N--;
return x.left;
}
// 如果x结点的左子树为空,则直接返回x的右子树
if (x.left == null) {
// 元素个数-1
N--;
return x.right;
}
// 如果x的左右子树都存在,则找到x结点右子树中的最小结点,并替换x结点
Node minNode = x.right;
while (minNode.left != null) {
minNode = minNode.left;
}
// 删除树中minNode结点
Node n = x.right;
while (n.left != null) {
if (n.left == minNode) {
n.left = null;
}
n = n.left;
}
// 用minNode替换x结点,让minNode的左右子树成为x的左右子树
minNode.left = x.left;
minNode.right = x.right;
// 元素个数-1
N--;
// 返回删除后更换子树()
x = minNode;
}
return x;
}
// 查找树中最小的键
public Key min() {
return min(root).key;
}
// 查找指定树中最小的键所在的结点
private Node min(Node x) {
// 判断x结点是否还有左子树,有继续向左遍历,没有则就是最小的结点
if (x.left != null) {
return min(x.left);
} else {
return x;
}
}
// 查找树中最大的键
public Key max() {
return max(root).key;
}
// 查找树中最大键所在的结点
private Node max(Node x) {
// 判断x结点是否还有右子树,有继续向左遍历,没有则就是最大的结点
if (x.right != null) {
return max(x.right);
} else {
return x;
}
}
// 结点类
private class Node {
// 存储键
private Key key;
// 存储值
private Value value;
// 记录左子结点
private Node left;
// 记录右子结点
private Node right;
public Node(Key key, Value value, Node left, Node right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
}