1. 映射的定义:映射就是存储( 键,值 )数据对的数据结构( Key,Value ) , 根据键(Key),寻找值(Value), 可以由链表实现映射LinkedMap ,是有序的;也可以由二分搜索树实现映射TreeMap,是有序的,并且键自然排序。映射中的键具有唯一性,不能重复;而键对应的值可以重复。
2. 映射接口的定义:
public interface Map<K, V> {
//向map中添加键值对
public void put(K key, V value);
//删除map中指定key的键值对
public V remove(K key);
//判断二分搜索树中是否包含指定key
public boolean contains(K key);
//通过key从map中获取key对应的值
public V get(K key);
//修改指定key对应的值
public void set(K key, V value);
//获取map中有效元素的个数
public int size();
//判断map是否为空
public boolean isEmpty();
//获取map中的键的集合 因为map中键key是唯一的 所以用集合set进行存储
public Set<K> keySet();
//获取map中的值的列表 因为map中键value不是唯一的 所以用列表list进行存储
public List<V> values();
//获取map中键值对的集合 因为map中键值对(key:value)是唯一的 所以用集合set进行存储
public Set<Entry<K, V>> entrySet();
//定义一个获取键值对Entry<K, V>的接口
public interface Entry<K, V> extends Comparable<Entry<K, V>>{
//获取键值对的键
public K getKey();
//获取键值对的值
public V getValue();
}
}
3. 底层通过二分搜索树实现的映射:( 许多操作类似于二分搜索树,但是不能完全使用二分搜索树,因为二分搜索树中存储的节点只有一个数据域,而映射需要包含两个数据一个是键,一个是键对应的值 )。
//定义底层通过二分搜索树实现的映射map
//二分搜索树中的数据必须具有可比性 因此映射中的键必须都是Comparable实现子类 因为键具有唯一性
public class TreeeMap<K extends Comparable<K>, V> implements Map<K, V>{
//定义二分搜索树节点的信息
//由四部分组成 键 值 指向左孩子的指针 指向右孩子的指针
private class Node {
K key; //键
V value; //值
Node leftChild; //左孩子指针域 指向当前节点左孩子
Node rightChild; //右孩子指针域 指向当前节点右孩子
public Node() {}
public Node(K key, V value) {
this.key = key;
this.value = value;
this.leftChild = null;
this.rightChild = null;
}
}
private Node root; //根节点的指针 如果二分搜索树为空 则root==null
private int size; //二分搜索树中元素的个数(键值对的个数)
public TreeeMap() {
root = null;
size = 0;
}
//辅助方法 获取以node为根节点的二分搜索树中 键为key的节点
private Node getNode(Node node, K key) {
if(node == null) {
return null;
}
if(key.compareTo(node.key) < 0) {
return getNode(node.leftChild, key);
}else if(key.compareTo(node.key) > 0) {
return getNode(node.rightChild, key);
}else {
return node;
}
}
//向map中添加键值对 向外提供的
@Override
public void put(K key, V value) {
root = put(root, key, value);
}
//向以node为根节点的二分搜索树中添加指定键值对 如果已经存在 则修改指定key的值为value
private Node put(Node node, K key, V value) {
if(node == null) {
size++;
return new Node(key, value);
}
if(key.compareTo(node.key) < 0) {
node.leftChild = put(node.leftChild, key, value);
}else if(key.compareTo(node.key) > 0) {
node.rightChild = put(node.rightChild, key, value);
}else {
node.value = value;
}
return node;
}
//删除map中指定key的键值对 并返回要删除键的值 向外提供的
@Override
public V remove(K key) {
Node ret = getNode(root, key);
if(ret == null) {
return null;
}
root = remove(root, key);
return ret.value;
}
//删除以node为根节点的二分搜索树中指定键值对
private Node remove(Node node, K key) {
if(node == null) {
return null;
}
if(key.compareTo(node.key) < 0) {
node.leftChild = remove(node.leftChild, key);
return node;
}else if(key.compareTo(node.key) > 0) {
node.rightChild = remove(node.rightChild, key);
return node;
}else {
if(node.leftChild == null) {
Node rightNode = node.rightChild;
node.rightChild = null;
size--;
return rightNode;
}else if(node.rightChild == null) {
Node leftNode = node.leftChild;
node.leftChild = null;
size--;
return leftNode;
}
Node successor = getMinNum(root);
successor.rightChild = removeMin(root);
successor.leftChild = node.leftChild;
node.leftChild = node.rightChild = null;
return successor;
}
}
//删除以node为根节点的二分搜索树的最小值
private Node removeMin(Node node) {
if(node.leftChild == null) {
Node rightNode = node.rightChild;
node.rightChild = null;
size--;
return rightNode;
}
node.leftChild = removeMin(node.leftChild);
return node;
}
//获取以node为根节点的二分搜索树的最小值
private Node getMinNum(Node node) {
if(node.leftChild == null) {
return node;
}
return getMinNum(node.leftChild);
}
//判断二分搜索树中是否包含指定key
@Override
public boolean contains(K key) {
return getNode(root, key) != null;
}
//通过key从map中获取key对应的值
@Override
public V get(K key) {
Node node = getNode(root, key);
if(node == null) {
throw new IllegalArgumentException("key is not exist");
}
return node.value;
}
//修改指定key对应的值
@Override
public void set(K key, V value) {
Node node = getNode(root, key);
if(node == null) {
throw new IllegalArgumentException("key-value is not exist");
}
node.value = value;
}
//获取map中有效元素的个数
@Override
public int size() {
return size;
}
//判断map是否为空
@Override
public boolean isEmpty() {
return size == 0 && root == null;
}
//获取map中的键的集合 因为map中键key是唯一的 所以用集合set进行存储
@Override
public Set<K> keySet() {
TreeSet<K> set = new TreeSet<K>();
inOrderKeySet(root, set);
return set;
}
//中序遍历以node节点为根节点的二分搜索树中的键 并将结果存放在指定集合set中
private void inOrderKeySet(Node node, TreeSet<K> set) {
if(node == null) {
return;
}
inOrderKeySet(node.leftChild, set);
set.add(node.key);
inOrderKeySet(node.rightChild, set);
}
//获取map中的值的列表 因为map中键value不是唯一的 所以用列表list进行存储
@Override
public List<V> values() {
LinkedList<V> list = new LinkedList<V>();
inOrderValues(root, list);
return list;
}
//中序遍历以node节点为根节点的二分搜索树的值 并将结果存放在指定列表list中
private void inOrderValues(Node node, LinkedList<V> list) {
if(node == null) {
return;
}
inOrderValues(node.leftChild, list);
list.add(node.value);
inOrderValues(node.rightChild, list);
}
//获取map中键值对的集合 因为map中键值对(key:value)是唯一的 所以用集合set进行存储
@Override
public Set<Entry<K, V>> entrySet() {
TreeSet<Entry<K, V>> set = new TreeSet<Entry<K,V>>();
inOrderEntries(root, set);
return set;
}
//中序遍历以node节点为根节点的二分搜索树的键值对 并将结果存放在指定集合set中
private void inOrderEntries(Node node, TreeSet<Entry<K, V>> set) {
if(node == null) {
return;
}
inOrderEntries(node.leftChild, set);
set.add(new BSTEntry(node.key, node.value));
inOrderEntries(node.rightChild, set);
}
//定义一个获取键值对Entry<K, V>的实现类 来封装键值对
/*
* 用treeSet来存储键值对 treeSet底层又是通过二分搜索树实现的
* 因此treeSet存储的内容必须具有可比性 所以键值对的实现类中必须重写compareTo方法
* 键值对中的键又要具有可比性 因此键也要继承于Comparable
*/
private class BSTEntry<K extends Comparable<K>, V> implements Entry<K, V>{
public K key;
public V value;
public BSTEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() { //获取键值对的键
return key;
}
@Override
public V getValue() { //获取键值对的值
return value;
}
//规定键的比较规则
@Override
public int compareTo(Entry<K, V> o) {
return this.key.compareTo(o.getKey());
}
//规定键值对的输出格式
@Override
public String toString() {
return key + ":" + value;
}
}
}