本文利用二叉查找树写了一个Map,用来保存键值对。
二叉查找树的定义
二叉查找树又名二叉搜索树,英文名称是 Binary Search Tree,缩写BST。
二叉排序树,英文名称是 Binary Sorted Tree,缩写BST。
二叉查找树、二叉搜索树、二叉排序树,这三者是一回事,只是名字不同。
二叉查找树的定义如下:
二叉查找树或者是一棵空树,或者是具有下列性质的二叉树:
-
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。
-
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
-
它的左、右子树也分别为二叉查找树。
二叉查找树的时间复杂度和空间复杂度
Java8代码实现
二叉查找树的节点类:
package zhangchao.bst;
/**
*
* 二叉查找树的节点类。
*
* @author zhangchao
*
* @param <K> 二叉查找树的键。
* @param <V> 二叉查找树的值。
*/
public class BstTreeMapNode<K,V> {
// 键
public K key = null;
// 值
public V value = null;
// 父节点的引用。
public BstTreeMapNode parent = null;
// 左子节点的引用。
public BstTreeMapNode left = null;
// 右子节点的引用。
public BstTreeMapNode right = null;
}
二叉查找树写的 BstTreeMap
package zhangchao.bst;
import java.util.*;
/**
* 利用二叉查找树实现的Map
*
* @author zhangchao
*
* @param <K> 键
* @param <V> 值
*/
public class BstTreeMap<K, V> {
// 根节点
private BstTreeMapNode root = null;
// 用户自定义的比较器
private Comparator<K> comparator;
/**
* 构造方法
* @param comparator 用户自定义的比较器
*/
public BstTreeMap(Comparator<K> comparator) {
this.comparator = comparator;
}
/**
* 向map中放入键值对
* @param key 键
* @param value 值
*/
public void put(K key, V value) {
if (null == root) {
root = new BstTreeMapNode<K, V>();
root.parent = null;
root.key = key;
root.value = value;
return;
}
BstTreeMapNode<K, V> parent = null;
BstTreeMapNode<K, V> current = root;
int compareResult = 0;
while (null != current) {
compareResult = this.comparator.compare(key, current.key);
if (compareResult < 0) {
parent = current;
current = current.left;
} else if (compareResult > 0) {
parent = current;
current = current.right;
} else {
// 有相等的key,直接设置值就可以了。
current.value = value;
return;
}
}
BstTreeMapNode<K, V> newItem = new BstTreeMapNode<K, V>();
newItem.key = key;
newItem.value = value;
newItem.parent = parent;
if (compareResult < 0) {
parent.left = newItem;
} else if (compareResult > 0) {
parent.right = newItem;
}
}
/**
* 根据键获取值
* @param key 键
* @return 值
*/
public V get(K key) {
BstTreeMapNode<K, V> current = root;
int compareResult;
while (null != current) {
compareResult = this.comparator.compare(key, current.key);
if (compareResult < 0) {
current = current.left;
} else if (compareResult > 0) {
current = current.right;
} else {
// 有相等的key,直接返回值就可以了。
return current.value;
}
}
return null;
}
/**
* 获取键的列表,按照比较器的顺序排列。
* @return 键的列表,按照比较器的顺序排列。
*/
public List<K> keyList() {
if (null == root) {
return new ArrayList<K>();
}
List<K> result = new ArrayList<K>();
Stack<BstTreeMapNode> stack = new Stack<>();
BstTreeMapNode<K, V> current = root;
do {
while (null != current) {
stack.push(current);
current = current.left;
}
current = stack.pop();
result.add(current.key);
current = current.right;
} while (!stack.isEmpty() || null != current);
return result;
}
/**
* 是否为空。
* @return true表示为空;false表示不为空。
*/
public boolean isEmpty() {
return null == root;
}
/**
* 根据键获取 BST 树的节点。
* @param key 键
* @return BST树的节点
*/
public BstTreeMapNode<K, V> getNode(K key) {
BstTreeMapNode<K, V> current = root;
int compareResult;
while (null != current) {
compareResult = this.comparator.compare(key, current.key);
if (compareResult < 0) {
current = current.left;
} else if (compareResult > 0) {
current = current.right;
} else {
// 有相等的key,直接返回值就可以了。
return current;
}
}
return null;
}
/**
* 根据键删除键值对。
* @param key 键
*/
public void remove(K key) {
BstTreeMapNode<K, V> node = getNode(key);
if (null == node) {
return;
}
// 叶子节点
if (null == node.left && null == node.right) {
if (node == root) {
this.root = null;
} else if (node == node.parent.left) {
node.parent.left = null;
} else if (node == node.parent.right) {
node.parent.right = null;
}
node.parent = null;
}
// 只有左子节点
else if (null != node.left && null == node.right) {
if (node == root) {
this.root = node.left;
} else if (node == node.parent.left) {
node.parent.left = node.left;
} else if (node == node.parent.right) {
node.parent.right = node.left;
}
node.left.parent = node.parent;
node.parent = null;
node.left = null;
}
// 只有右子节点
else if (null == node.left && null != node.right) {
if (node == root) {
this.root = node.right;
} else if (node == node.parent.left) {
node.parent.left = node.right;
} else if (node == node.parent.right) {
node.parent.right = node.right;
}
node.right.parent = node.parent;
node.parent = null;
node.right = null;
}
// 不是根节点并且有左右子节点。
else {
BstTreeMapNode<K,V> current = node.left;
while (null != current.right) {
current = current.right;
}
if (current == current.parent.left) {
current.parent.left = current.left;
} else if (current == current.parent.right) {
current.parent.right = current.left;
}
if (null != current.left) {
current.left.parent = current.parent;
}
current.parent = node.parent;
current.left = node.left;
current.right = node.right;
if (null != node.left) {
node.left.parent = current;
}
if (null != node.right) {
node.right.parent = current;
}
if (null == node.parent) {
this.root = current;
} else if (node == node.parent.left) {
node.parent.left = current;
} else if (node == node.parent.right) {
node.parent.right = current;
}
// 清理被删除节点的关联引用
node.left = null;
node.right = null;
node.parent = null;
}
}
/**
* 计算map的键值对数量。
* @return map的键值对数量。
*/
public int size() {
return this.keyList().size();
}
/**
* 清空map,删除所有的键值对。
*/
public void clear() {
List<K> keyList = this.keyList();
if (null != keyList && !keyList.isEmpty()) {
for (K key : keyList) {
this.remove(key);
}
}
}
private void showTree(BstTreeMapNode node, int level, String prefix) {
if (null == node) {
return;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < level; i++) {
sb.append(" ");
}
sb.append(prefix);
sb.append(node.key).append(" ");
if (node.parent != null) {
sb.append(node.parent.key);
}
System.out.println(sb);
level++;
showTree(node.left, level, "left : ");
showTree(node.right, level, "right: ");
}
/**
* 打印树形结构。
*/
public void showTree() {
if (null == root) {
System.out.println("null");
}
showTree(root, 0, "root: ");
}
}
测试例子
TestBST
package zhangchao.bst;
import java.util.Comparator;
import java.util.List;
public class TestBST {
public static void test1() {
BstTreeMap<Integer, String> map = new BstTreeMap<>( (o1, o2) -> (o1 - o2) );
int[] arr = new int[]{8,3,6,1,2,98,2,6};
for (int i : arr) {
map.put(i, "__" + String.valueOf(i));
}
System.out.println(map.get(3));
System.out.println(map.get(6));
System.out.println(map.get(98));
List<Integer> keyList = map.keyList();
for (Integer key : keyList) {
String value = map.get(key);
System.out.println(key + " : " + value);
}
System.out.println();
map.showTree();
map.remove(2);
System.out.println(map.get(2));
}
public static void test2() {
BstTreeMap<String, String> map = new BstTreeMap(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if (null == o1 && null == o2) {
return 0;
}
if (null == o1 && null != o2) {
return -1;
}
if (null != o1 && null == o2) {
return 1;
}
return o1.compareTo(o2);
}
});
String[] arr = {"j", "h", "e", "a", "e", "z", "d", "i", "y", "a", "u", "k", "u", "g", null};
for (String i : arr) {
map.put(i, "__" + String.valueOf(i));
}
System.out.println("Before:");
map.showTree();
String key = "z";
map.remove(key);
System.out.println(map.get(key));
System.out.println("After:");
map.showTree();
System.out.println("map.get(null)=" + map.get(null));
System.out.println("map.size()=" + map.size());
map.remove(null);
System.out.println("After remove(null), map.get(null)=" + map.get(null));
System.out.println("After remove(null), map.showTree() ");
map.showTree();
System.out.println("map.isEmpty()=" + map.isEmpty());
map.clear();
System.out.println("After clear, map.showTree() ");
map.showTree();
System.out.println("map.isEmpty()=" + map.isEmpty());
}
// 测试删除根节点
public static void test3() {
BstTreeMap<Integer, String> map = new BstTreeMap<>( (o1, o2) -> (o1 - o2) );
int[] arr = new int[]{100,50,150,25,75,125,190,12,40,60,30};
for (int i : arr) {
map.put(i, "__" + String.valueOf(i));
}
System.out.println("Before:");
map.showTree();
int key = 100;
map.remove(key);
System.out.println("map.get(100)" + map.get(key));
System.out.println("After:");
map.showTree();
map.remove(75);
System.out.println("map.get(75)" + map.get(75));
System.out.println("After:");
map.showTree();
}
public static void test4() {
// 根节点是叶子节点
BstTreeMap<Integer, String> map = new BstTreeMap<>( (o1, o2) -> (o1 - o2) );
map.put(4, "_4");
map.showTree();
map.remove(4);
System.out.println("map.get(4)=" + map.get(4));
map.showTree();
System.out.println("----------------------");
// 根节点只有左子节点
map.put(3, "_3");
map.put(2, "_2");
map.put(1, "_1");
map.showTree();
map.remove(3);
System.out.println("map.get(3)=" + map.get(3));
map.showTree();
map.remove(2);
System.out.println("map.get(2)=" + map.get(2));
map.showTree();
map.remove(1);
System.out.println("----------------------");
// 根节点只有右子节点
map.put(1, "_1");
map.put(2, "_2");
map.put(3, "_3");
map.showTree();
map.remove(1);
System.out.println("map.get(1)=" + map.get(1));
map.showTree();
map.remove(2);
System.out.println("map.get(2)=" + map.get(2));
map.showTree();
map.remove(3);
System.out.println("----------------------");
}
public static void test5() {
BstTreeMap<Integer, String> map = new BstTreeMap<>( (o1, o2) -> (o1 - o2) );
int[] arr = new int[]{100,50,150,25,75,125,190,12,40,60,30};
for (int i : arr) {
map.put(i, "__" + String.valueOf(i));
}
System.out.println("Before:");
map.showTree();
// int key = 50;
int key = 150;
map.remove(key);
System.out.println(map.get(key));
System.out.println("After:");
map.showTree();
}
public static void main(String[] args) {
test2();
}
}