定义:只有两个子节点的树称为二叉树 满二叉树:如果一个二叉树,每一层的结点树都达到最大值,则为满二叉树 完全二叉树:上一层未满的情况下不允许插入元素 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(根节点) 即为最大深度。
|