二叉树
1.二叉树遍历
1.1 前序遍历:按照根结点->左子树->右子树的顺序访问
1.2 中序遍历:按照左子树->根结点->右子树的顺序访问
1.3 后序遍历:按照左子树->右子树->根结点的顺序访问
2.前序遍历,中序遍历与后序遍历之间的推导
- 已知前序和中序:
①从前序中找根结点root1
②在中序中根据根结点root1将其分为左子树和右子树
③从前序中找左子树的根结点root2
④在中序中将左子树根据根结点root2将左子树又分为左子树和右子树
循环上述过程,画出二叉树图,再得到后序遍历 - 已知中序和后序:
提示:后序的最后一个为树的根结点 - 已知前序和后序:答案不唯一
3.二叉树的性质
- 在二叉树的第i层上最多有2(i-1)个结点
- 二叉树中如果深度为k(有k层),那么最多有2^k - 1个结点
4.二叉树的形态
- 完美二叉树(满二叉树 Perfect Binary Tree, BST)
高度为k的二叉树有2^k - 1个结点 - 完全二叉树(Complete Binary Tree, CBT)
从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐
叶子结点的最大深度与最小深度差不超过1 - 完满二叉树(Full Binary Tree, FBT)
所有非叶子结点的度都是2 - 三者的比较
- 平衡二叉树(Balanced Binary Tree)
任意结点的左子树与右子树高度差不超过1
5.二分搜索树(Binary Search Tree, BST)
5.1 二分搜索树的整体代码
import java.util.LinkedList;
import java.util.Queue;
public class BST<E extends Comparable<E>> {
private class Node {
public E e;
public Node left;
public Node right;
public Node(E e) {
this.e = e;
this.left = null;
this.right = null;
}
}
private Node root;
private int size;
public BST() {
root = null;
size = 0;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void add(E e) {
root = add(root, e);
}
// return the root node after add a new node
private Node add(Node node, E e) {
if (node == null) {
size++;
return new Node(e);
}
if (e.compareTo(node.e) < 0) {
node.left = add(node.left, e);
} else if (e.compareTo(node.e) > 0) {
node.right = add(node.right, e);
}
return node;
}
public boolean contains(E e) {
return contains(root, e);
}
private boolean contains(Node node, E e) {
if (node == null) {
return false;
}
if (e.compareTo(node.e) < 0) {
return contains(node.left, e);
} else if (e.compareTo(node.e) == 0) {
return true;
} else {
return contains(node.right, e);
}
}
public void preOrder(Node node) {
if (node == null) {
return;
}
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
public void inOrder(Node node) {
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
public void postOrder(Node node) {
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
public void levelOrder() {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
Node cur = queue.remove();
System.out.println(cur.e);
if (cur.left != null) {
queue.add(cur.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
}
}
public E minimum() {
if (size == 0) {
throw new IllegalArgumentException("BST is empty!");
}
return minimum(root).e;
}
private Node minimum(Node node) {
if (node.left == null) {
return node;
}
return minimum(node.left);
}
public E removeMin() {
E ret = minimum();
root = removeMin(root);
return ret;
}
private Node removeMin(Node node) {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
public E maximum() {
if (size == 0) {
throw new IllegalArgumentException("BST is empty!");
}
return maximum(root).e;
}
private Node maximum(Node node) {
if (node.right == null) {
return node;
}
return maximum(node.right);
}
public E removeMax() {
E ret = maximum();
root = removeMax(root);
return ret;
}
private Node removeMax(Node node) {
if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
public void remove(E e) {
root = remove(root, e);
}
private Node remove(Node node, E e) {
if (node == null) {
return null;
}
if (e.compareTo(node.e) < 0) {
node.left = remove(node.left, e);
return node;
} else if (e.compareTo(node.e) > 0) {
node.right = remove(node.right, e);
return node;
} else {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
Node successor = minimum(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
}
5.2 add method
5.2.1 非递归实现(not recursion)
public void add(E e) {
Node node = new Node(e);
if (root == null) {
root = node;
size++;
} else {
Node temp = root;
while (temp != null) {
if (e.compareTo(temp.e) < 0) {
if (temp.left == null) {
temp.left = node;
size++;
return;
} else {
temp = temp.left;
}
} else {
if (temp.right == null) {
temp.right = node;
szie++;
return;
} else {
temp = temp.right;
}
}
}
}
}
5.2.2 递归实现(recursion)
public void add(E e) {
if (root == null) {
root = new Node(e);
size++;
} else {
add(root, e);
}
}
private void add(Node node, E e) {
if (e.equals(node.e)) {
return;
} else if (e.compareTo(node.e) < 0 && node.left == null) {
node.left = new Node(e);
size++;
return;
} else if (e.compareTo(node.e) > 0 && node.right == null) {
node.right = new Node(e);
size++;
return;
}
if (e.compareTo(node.e) < 0) {
add(node.left, e);
} else {
add(node.right, e);
}
}
5.2.3 递归实现(optimize and refactor recursion method)
// recurse method optimization and refactor
public void add(E e) {
root = add(root, e);
}
//return the root node after add a new node
private Node add(Node node, E e) {
if (node == null) {
size++;
return new Node(e);
}
if (e.compareTo(node.e) < 0) {
node.left = add(node.left, e);
} else if (e.compareTo(node.e) > 0) {
node.right = add(node.right, e);
}
return node;
}
5.3 search method
5.3.1 非递归实现(not recursion)
public boolean contains(E e) {
Node temp = root;
while (temp != null) {
if (e.compareTo(temp.e) == 0) {
return true;
} else if (e.compareTo(temp.e) < 0) {
temp = temp.left;
} else {
temp = temp.right;
}
}
return false;
}
5.3.2 递归实现(recursion)
public boolean contains(E e) {
return contains(root, e);
}
private boolean contains(Node node, E e) {
if (node == null) {
return false;
}
if (e.compareTo(node.e) < 0) {
return contains(node.left, e);
} else if (e.compareTo(node.e) == 0) {
return true;
} else {
return contains(node.right, e);
}
}
5.4 traversal method
5.4.1 非递归实现(not recursion)
用到了栈(stack)实现
public void preOrder() {
Stack < Node > stack = new Stack < > ();
stack.push(root);
while (!stack.isEmpty()) {
Node cur = stack.pop();
System.out.println(cur.e);
if (cur.right != null) {
stack.push(cur.right);
}
if (cur.left != null) {
stack.push(cur.left);
}
}
}
5.4.2 递归实现(recursion)
public void preOrder(Node node) {
if (node == null) {
return;
}
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
6.AVL树
6.1 AVL树的左旋与右旋
6.1.1 AVL树的左旋与右旋的规则
6.1.2 AVL树的左旋与右旋的实例
备注:在左旋和右旋时需要重新计算height值
6.2 AVL树的整体代码
import java.util.Queue;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
public class AVLTree<K extends Comparable<K>, V> {
private class Node {
public K key;
public V value;
public Node left;
public Node right;
public int height;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
this.height = 1;
}
}
private Node root;
private int size;
public AVLTree() {
root = null;
size = 0;
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
// 计算高度
public int getHeight(Node node) {
if (node == null) {
return 0;
}
return node.height;
}
// 计算平衡因子
private int getBalanceFactor(Node node) {
if (node == null) {
return 0;
}
return getHeight(node.left) - getHeight(node.right);
}
// 判断是否为二分搜索树
public boolean isBST() {
List<K> keys = new ArrayList<>();
inOrder(root, keys);
for (int i = 1; i < keys.size(); i++) {
if (keys.get(i).compareTo(keys.get(i - 1)) < 0) {
return false;
}
}
return true;
}
private void inOrder(Node node, List<K> keys) {
if (node == null) {
return;
}
inOrder(node.left, keys);
keys.add(node.key);
inOrder(node.right, keys);
}
// 判断是否为平衡二叉树
public boolean isBalanced() {
return isBalanced(root);
}
private boolean isBalanced(Node node) {
if (node == null) {
return true;
}
int balanceFactor = getBalanceFactor(node);
if (Math.abs(balanceFactor) > 1) {
return false;
}
return isBalanced(node.left) && isBalanced(node.right);
}
private Node getNode(Node node, K key) {
if (node == null) {
return null;
}
if (key.compareTo(node.key) < 0) {
return getNode(node.left, key);
} else if (key.compareTo(node.key) > 0) {
return getNode(node.right, key);
} else {
return node;
}
}
public boolean contains(K key) {
return getNode(root, key) != null;
}
public void preOrder() {
preOrder(root);
}
private void preOrder(Node node) {
if (node == null) {
return;
}
System.out.println(node.key);
preOrder(node.left);
preOrder(node.right);
}
public void inOrder() {
inOrder(root);
}
private void inOrder(Node node) {
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node.key);
inOrder(node.right);
}
public void postOrder() {
postOrder(root);
}
private void postOrder(Node node) {
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node.key);
}
public void levelOrder() {
Queue<Node> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
Node cur = q.remove();
System.out.println(cur.key);
if (cur.left != null) {
q.add(cur.left);
}
if (cur.right != null) {
q.add(cur.right);
}
}
}
public V get(K key) {
Node node = getNode(root, key);
return node == null ? null : node.value;
}
public void set(K key, V newValue) {
Node node = getNode(root, key);
if (node == null) {
throw new IllegalArgumentException(key + "doesn't exist!");
}
node.value = newValue;
}
// 右旋
// y x
// / \ / \
// x T4 向右旋转(y) z y
// / \ - - - - - - -> / \ / \
// z T3 T1 T2 T3 T4
// / \
// T1 T2
private Node rightRotate(Node y) {
Node x = y.left;
Node T3 = x.right;
x.right = y;
y.left = T3;
y.height = 1 + Math.max(getHeight(y.left), getHeight(y.right));
x.height = 1 + Math.max(getHeight(x.left), getHeight(x.right));
return x;
}
// 左旋
// y x
// / \ / \
// T1 x 向左旋转(y) y z
// / \ - - - - - - -> / \ / \
// T2 z T1 T2 T3 T4
// / \
// T3 T4
private Node leftRotate(Node y) {
Node x = y.right;
Node T2 = x.left;
x.left = y;
y.right = T2;
y.height = 1 + Math.max(getHeight(y.left), getHeight(y.right));
x.height = 1 + Math.max(getHeight(x.left), getHeight(x.right));
return x;
}
public void add(K key, V value) {
root = add(root, key, value);
}
private Node add(Node node, K key, V value) {
if (node == null) {
size++;
return new Node(key, value);
}
if (key.compareTo(node.key) < 0) {
node.left = add(node.left, key, value);
}
if (key.compareTo(node.key) > 0) {
node.right = add(node.right, key, value);
} else {
node.value = value;
}
// 计算高度
node.height = 1 + Math.max(getHeight(node.left), getHeight(node.right));
// 计算平衡因子
int balanceFactor = getBalanceFactor(node);
// LL
if (balanceFactor > 1 && getBalanceFactor(node.left) >= 0) {
return rightRotate(node);
}
// RR
if (balanceFactor < -1 && getBalanceFactor(node.right) <= 0) {
return leftRotate(node);
}
// LR
if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// RL
if (balanceFactor < -1 && getBalanceFactor(node.right) > 0) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}
public K findMin() {
if (size == 0) {
throw new IllegalArgumentException("Can not find something from a blank tree.");
}
return findMin(root).key;
}
private Node findMin(Node node) {
if (node.left == null) {
return node;
}
return findMin(node.left);
}
public K removeMin() {
K ret = findMin();
root = removeMin(root);
return ret;
}
private Node removeMin(Node node) {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
public void remove(K key) {
root = remove(root, key);
}
private Node remove(Node node, K key) {
if (node == null) {
return null;
}
Node retNode;
if (key.compareTo(node.key) < 0) {
node.left = remove(node.left, key);
retNode = node;
} else if (key.compareTo(node.key) > 0) {
node.right = remove(node.right, key);
retNode = node;
} else {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
retNode = rightNode;
} else if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
retNode = leftNode;
} else {
Node successor = findMin(node.right);
// successor.right = removeMin(node.right);
successor.right = remove(node.right, successor.key);
successor.left = node.left;
node.left = node.right = null;
retNode = successor;
}
}
if (retNode == null) {
return null;
}
retNode.height = 1 + Math.max(getHeight(retNode.left), getHeight(retNode.right));
int balanceFactor = getBalanceFactor(retNode);
// LL
if (balanceFactor > 1 && getBalanceFactor(retNode.left) >= 0) {
return rightRotate(retNode);
}
// RR
if (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) {
return leftRotate(retNode);
}
// LR
if (balanceFactor > 1 && getBalanceFactor(retNode.left) < 0) {
retNode.left = leftRotate(retNode.left);
return rightRotate(retNode);
}
// RL
if (balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) {
retNode.right = rightRotate(retNode.right);
return leftRotate(retNode);
}
return retNode;
}
}
7.红黑树(Red Black Tree, RBT)
等价于2-3树(2-3树具有绝对平衡性),在添加和删除性能上优于AVL树
1. 所有结点的颜色不是红色就是黑色
2. 根结点的颜色为黑色
3. 每一个叶子结点(最后的空节点)是黑色的
4. 红色结点的两个孩子都为黑色
5. 从任意结点出发到叶子结点经过的黑色结点数量相同