(一) 定义
映射Map: 存储(键, 值)数据对的数据结构(Key, Value), 我们可以根据键(Key)来寻找值(Value), 且key在映射中是唯一的.实现映射的方式多种多样, 在JAVA语言表现中, 会将映射定义成一个接口, 提供映射对应的操作的抽象方法.
/**
* 自定义映射抽象类Map
*
* @author Administrator
*
* @param <K>
* @param <V>
*/
public interface Map<K, V> {
/**
* 向映射中添加键值对数据(Key键不允许重复)
*
* @param key
* @param value
*/
void add(K key, V value);
/**
* 从映射中删除键为key的数据
*
* @param key
* @return
*/
V remove(K key);
/**
* 映射中是否存在key
*
* @param key
* @return
*/
boolean contains(K key);
/**
* 从映射中取出key键 对应的value值
*
* @param key
* @return
*/
V get(K key);
/**
* 修改映射中key对应的value值
*
* @param key
* @param value
*/
void set(K key, V value);
/**
* 映射中键值对个数
*
* @return
*/
int getSize();
/**
* 映射是否为空
*
* @return
*/
boolean isEmpty();
}
(二) 自定义映射
1.基于链表的映射实现
public class LinkedListMap<K, V> implements Map<K, V> {
/**
* 节点内部类: 可以单独定义出来, 但用户无需关注映射底层实现, 因此定义成LinkedListMap的内部类
*
* @author Administrator
*
*/
private class Node {
/**
* 存储映射的键
*/
public K key;
/**
* 存储映射的值
*/
public V value;
/**
* 下一个结点
*/
public Node next;
public Node(K key, V value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
@SuppressWarnings("unused")
public Node(K key) {
this(key, null, null);
}
public Node() {
this(null, null, null);
}
@Override
public String toString() {
return key.toString() + " : " + value.toString();
}
}
/**
* 虚拟头部节点: 存储的数据为Null, 下一个节点next也为Null
*/
private Node dummyHead;
/**
* 映射键值对个数
*/
private int size;
public LinkedListMap() {
this.dummyHead = new Node();
this.size = 0;
}
@Override
public int getSize() {
return this.size;
}
@Override
public boolean isEmpty() {
return this.size == 0;
}
/**
* 获取key对应的结点
*
* @param key
* @return
*/
private Node getNode(K key) {
Node cur = this.dummyHead.next;
while(cur != null) {
if (cur.key.equals(key)) {
return cur;
}
cur = cur.next;
}
return null;
}
@Override
public boolean contains(K key) {
return getNode(key) != null;
}
@Override
public V get(K key) {
Node res = getNode(key);
return res == null ? null : res.value;
}
@Override
public void add(K key, V value) {
Node node = getNode(key);
if (node == null) {
// key键在映射中不存在, 添加新的结点
dummyHead.next = new Node(key, value, dummyHead.next);
size++;
} else {
// key键在映射中存在, 修改key所在的结点对应的值为 value
node.value = value;
}
}
@Override
public void set(K key, V value) {
Node node = getNode(key);
if (node == null) {
throw new IllegalArgumentException(key + " doesn't exist!");
}
node.value = value;
}
@Override
public V remove(K key) {
Node prev = this.dummyHead;
while (prev.next != null) {
if (prev.next.key.equals(key)) {
V value = prev.next.value;
prev.next = prev.next.next;
size--;
return value;
}
prev = prev.next;
}
return null;
}
}
2.基于二分搜索树的映射实现
public class BSTMap<K extends Comparable<K>, V> implements Map<K, V> {
/**
* 节点内部类: 可以单独定义出来, 但用户无需关注映射底层实现, 因此定义成BSTMap的内部类
*
* @author Administrator
*
*/
private class Node {
/**
* 存储映射的键
*/
public K key;
/**
* 存储映射的值
*/
public V value;
/**
* 左子树
*/
public Node left;
/**
* 右子树
*/
public Node right;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
}
/**
* 根结点
*/
private Node root;
/**
* 映射中键值对个数
*/
private int size;
public BSTMap() {
this.root = null;
this.size = 0;
}
@Override
public int getSize() {
return this.size;
}
@Override
public boolean isEmpty() {
return this.size == 0;
}
/**
* 向映射中添加键值对key-value(Key键不允许重复)
*/
@Override
public void add(K key, V value) {
this.root = add(this.root, key, value);
}
/**
* 向以node为根的二分搜索树中插入键值对key-value, 返回插入新节点后二分搜索树的跟
*
* @param node
* @param key
* @param value
* @return
*/
private Node add(Node node, K key, V value) {
if (node == null) {
size++;
return new Node(key, value);
}
// 二分搜索树中存在插入key, 修改key对应的value
if (node.key.compareTo(key) == 0) {
node.value = value;
} else if (node.key.compareTo(key) < 0) {
node.right = add(node.right, key, value);
} else if (node.key.compareTo(key) > 0) {
node.left = add(node.left, key, value);
}
return node;
}
/**
* 返回以node为根结点定的二分搜索树中, key所对应的结点
*
* @param key
* @return
*/
private Node getNode(Node node, K key) {
if (node == null) {
return null;
}
if (node.key.compareTo(key) == 0) {
return node;
} else if (node.key.compareTo(key) < 0) {
return getNode(node.right, key);
} else {
return getNode(node.left, key);
}
}
@Override
public boolean contains(K key) {
return getNode(root, key) != null;
}
@Override
public V get(K key) {
Node node = getNode(root, key);
return node == null ? null : node.value;
}
@Override
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;
}
/**
* 返回以node为根的二分搜索树的最小值所在的结点
*
* @param node
* @return
*/
private Node minimum(Node node) {
if (node.left != null) {
return node.left;
}
return minimum(node.left);
}
/**
* 向以node为根的二分搜索树中删除最小元素, 返回删除最小元素节点后二分搜索树的跟
*
* @param node
* @return
*/
private Node removeMin(Node node) {
if (node.left == null) {
Node delNode = node.right;
node.right = null;
size--;
return delNode;
}
node.left = removeMin(node.left);
return node;
}
/**
* 从映射中删除键为key的数据
*/
@Override
public V remove(K key) {
Node node = getNode(root, key);
if (node != null) {
root = remove(root, key);
return node.value;
}
return null;
}
/**
* 删除以node为根的二分搜索树中键为key的结点, 返回删除节点后新的二分搜索树的跟
*
* @param node
* @param key
* @return
*/
private Node remove(Node node, K key) {
if (node == null) {
return null;
}
if (node.key.compareTo(key) == 0) {
if (node.left == null) {
Node delNode = node.right;
node.right = null;
size--;
return delNode;
}
if (node.right == null) {
Node delNode = node.left;
node.left = null;
size--;
return delNode;
}
Node replaceNode = minimum(node.right);
replaceNode.right = removeMin(node.right);
replaceNode.left = node.left;
return replaceNode;
} else if (node.key.compareTo(key) < 0) {
node.right = remove(node.right, key);
} else {
node.left = remove(node.left, key);
}
return node;
}
}
(三) 时间复杂度分析
add(e)方法为了保证映射存储的key不重复, 内部调用了getNode(k) 方法
LinkedListMap | BSTMap | 平均 | 最差(链表) | |
---|---|---|---|---|
add(k, v) | O(n) | O(h) | O(logn) | O(n) |
remove(k) | O(n) | O(h) | O(logn) | O(n) |
contains(k) | O(n) | O(h) | O(logn) | O(n) |
get(k) | O(n) | O(h) | O(logn) | O(n) |
set(k, v) | O(n) | O(h) | O(logn) | O(n) |