|
定义:只有两个子节点的树称为二叉树
满二叉树:如果一个二叉树,每一层的结点树都达到最大值,则为满二叉树
完全二叉树:上一层未满的情况下不允许插入元素
1.结点类的实现:根结点、左子结点、右子结点
|
public class BinaryNode<Key extends Comparable<Key>,Value> {
public BinaryNode left;
public BinaryNode right;
public Key key;
public Value value;
public BinaryNode(BinaryNode left, BinaryNode right, Key key, Value value) {
this.left = left;
this.right = right;
this.key = key;
this.value = value;
}
}
|
2.二叉查找树的API设计:
|
类名
|
BinaryTree<Key extends Comparable<Key>>,Value value>
此处继承是为了之后进行排序
| |
构造方法
|
Public BinaryTree();
| |
成员变量
|
Private Node root;//根结点
Private int length;//结点的个数
| |
成员方法
|
1. public void put(key,value);//插入键值对
2. public Node put(Node x,key,value);//指定x树中插入键值对
3. public value get(key);//获取键对应的值
4. public value get(Node x,key);//删除指定树上键对应的值
5. public void delete(key);//
6. public value delete (Node x,key);//删除指定树上键对应的值
|


3.代码实现
增加:
|
/**
* 插入键值对
* @param key
* @param value
*/ public void put(Key key, Value value){
root = this.put(root,key,value); }
/**
* 指定x树中插入键值对
* @param x
* @param key
* @param value
*/ public BinaryNode put(BinaryNode x,Key key, Value value){
//如果x为空,则根节点即为key-value
if(x == null){
length++;
return new BinaryNode(null,null,key,value);
}
//如果x不为空,判断key与root.key的大小,
//key < root.key
if (key.compareTo((Key) x.key) < 0){
x.left = put(x.left,key,value);
}
//key > root.key
if (key.compareTo((Key) x.key) > 0){
x.right = put(x.right,key,value);
}
if (key.compareTo((Key) x.key) == 0){
x.value = value;
}
return x; }
|
※注意:
1.在put方法中,root根节点没有及时更新
2.结点实体类无需继承Comparable接口,而二叉树需要
获取:
|
/**
* 获取指定key的元素
* @param key
* @return
*/ public Value get(Key key){
return get(root,key); }
/**
* 获取指定二叉树的元素
* @param x
* @param key
* @return
*/ public Value get(BinaryNode x,Key key){
//如果x为空,直接返回空
if (x == null){
return null;
}
if (key.compareTo((Key) x.key) < 0){
return get(x.left,key);
}
//key > root.key
if (key.compareTo((Key) x.key) > 0){
return get(x.right,key);
}
if (key.compareTo((Key) x.key) == 0){
return (Value) x.value;
}
return null; }
|

- 当key=10删除时,需要找一个元素能够替代key=10
- 这个元素要满足,左子树都小于该结点元素、右子树都大于该结点元素,所以需要在key=10的右子树选择一个最小的元素
- 找到最小的元素后,删除该结点,并将最小结点元素指向要删除的key的左子树和右子树
|
/**
* 删除指定二叉树的元素
* @param x
* @param key
* @return
*/ public BinaryNode delete (BinaryNode x,Key key){
//如果x为空
if (x == null){
return null;
}
//key < root.key
if (key.compareTo((Key) x.key) < 0){
x.left = delete(x.left,key);
}
//key > root.key
if (key.compareTo((Key) x.key) > 0){
x.right = delete(x.right,key);
}
//key = root.key
if (key.compareTo((Key) x.key) == 0){
//1.找到右子树中最小的结点
//1.1 如果右子树为空
if(x.right == null){
return x.left;
}
//1.2 左子树为空
if (x.left == null){
return x.right;
}
//1.3 左右子树都不为空:找到最小的结点并删除
BinaryNode minNode = x.right;
while (minNode.left != null){
minNode = minNode.left;
}
//2.找到最小结点的上一个节点并删除最小节点
BinaryNode node = x.right;
while (node.left != null){
if(node.left.left == null)
node.left = null;
else
node = node.left;
}
//让x结点的左子树成为minnode的左子树
minNode.left = x.left;
//让x结点的右子树成为minnode的右子树
minNode.right = x.right;
//让x的父结点指向minnode
x = minNode;
}
length --;
return x; }
|
4.测试代码
|
public static void testBinaryTree(){
BinaryTree<Integer,String> tree = new BinaryTree<>();
tree.delete(2);
System.out.println("空树删除:" + tree.size());
tree.put(1,"Tracy");
tree.put(2,"Kobe");
tree.put(3,"James");
System.out.println("现有的元素的个数:" + tree.size());
String first = tree.get(3);
System.out.println("第一个元素为:" + first);
tree.delete(2);
System.out.println("删除后的元素的个数:" + tree.size()); }
|
|
public Key getMinKey(){
return (Key) getMinKey(root).key; } public BinaryNode getMinKey(BinaryNode x){
if (x == null)
return null;
if(x.left != null){
return getMinKey(x.left);
}
return x; }
|
|
public Key getMaxKey(){
return (Key) getMaxKey(root).key; } public BinaryNode getMaxKey(BinaryNode x){
if (x == null)
return null;
if(x.right != null){
return getMaxKey(x.right);
}
return x; }
|

- 前序(根→左→右)
FCADBEHGM
|
/**
* 二叉树的前序遍历
* @return
*/ public void preErgodic(BinaryNode x,Queue<Key> keys){
//1.判断根结点是否为空,为空直接返回null
if(x == null){
return;
}
keys.enqueue((Key) x.key);
//2.如果左子树不为空,则递归调用前序遍历
if(x.left != null){
preErgodic(x.left,keys);
}
//3.如果右子树不为空,则递归调用前序遍历
if(x.right != null){
preErgodic(x.right,keys);
}
}
|
|
测试:
public static void testPreErgodic() throws InterruptedException {
BinaryTree<String,String> tree = new BinaryTree<>();
tree.put("E","5");
tree.put("B","2");
tree.put("G","7");
tree.put("A","1");
tree.put("D","4");
tree.put("F","6");
tree.put("H","8");
tree.put("C","3");
Queue<String> result = tree.preErgodic();
for (int i=0;i<tree.size();i++){
System.out.println(tree.get(result.dequeue()));
}
}

|
- 中序(左→根→右)使用较多,可以排序
ACBDFHEMG
|
/**
* 二叉树的中序遍历
* @return
*/ public Queue<Key> midErgodic(){
Queue<Key> keys = new Queue<Key>();
this.midErgodic(root,keys);
return keys; }
/**
* 二叉树的中序遍历
* @return
*/ public void midErgodic(BinaryNode x,Queue<Key> keys){
//1.判断根结点是否为空,为空直接返回null
if(x == null){
return;
}
//2.先递归,把根节点的所有左子树存入keys
if(x.left != null){
midErgodic(x.left,keys);
}
//3.存入根节点
keys.enqueue((Key) x.key);
//4.递归存入所有右子树
if(x.right != null){
midErgodic(x.right,keys);
}
}
|
测试:

- 后序(左→右→根)
ABDCHMGEF
代码类似,自己完成。
- 层次遍历
主要思想:
计算左子树的最大深度M1,右子树最大深度M2,比较M1 与M2,取较大值+1(根节点)
即为最大深度。
|