映射(字典) - Map
- Map是以key,value的形式存储数据的;
- 在Map中,要求key是唯一的;
public interface Map<K, V> {
void add(K key, V value);
V remove(K key);
boolean contains(K key);
V get(K key);
void set(K key, V newValue);
int getSize();
boolean isEmpty();
}
基于LinkedList的Map实现 - 基础
- 基于链表的映射实现,其实就是节点包含key和value的链表;
- 链表的节点node,包含key和value;
- Node getNode(K key)是根据key,获取包含key的整个节点node;
public class LinkedListMap<K, V> implements Map<K, V> {
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;
}
public Node(K key, V value){
this(key, value, null);
}
public Node(){
this(null, null, null);
}
@Override
public String toString(){
return key.toString() + " : " + value.toString();
}
}
private Node dummyHead;
private int size;
public LinkedListMap(){
dummyHead = new Node();
size = 0;
}
@Override
public int getSize(){
return size;
}
@Override
public boolean isEmpty(){
return size == 0;
}
private Node getNode(K key){
Node cur = dummyHead.next;
while(cur != null){
if(cur.key.equals(key))
return cur;
cur = cur.next;
}
return null;
}
}
根据key在Map中查找是否存在该key - boolean contains(K key)
@Override
public boolean contains(K key){
return getNode(key) != null;
}
根据key获取value - V get(K key)
@Override
public V get(K key){
Node node = getNode(key);
return node == null ? null : node.value;
}
向Map中添加键值对 - void add(K key, V value)
- 先看原有链表中有没有该键值对:
- 如果没有,将该键值对添加到链表的表头;
- 如果有,更新该键值对的value;
@Override
public void add(K key, V value){
Node node = getNode(key);
if(node == null){
dummyHead.next = new Node(key, value, dummyHead.next);
size ++;
}
else
node.value = value;
}
更新Map中的键值对 - void set(K key, V newValue)
- 先看原有链表中有没有该键值对:
- 如果没有,抛异常;
- 如果有,更新该键值对的value;
@Override
public void set(K key, V newValue){
Node node = getNode(key);
if(node == null)
throw new IllegalArgumentException(key + " doesn't exist!");
node.value = newValue;
}
根据key删除键值对 - V remove(K key)
- 从第一个节点开始遍历,看包含key的键值对存不存在;
- 如果该键值对存在,删除该键值对,链表的size减1,并返回该键值对的value;
- 如果该键值对不存在,返回null;
@Override
public V remove(K key){
Node prev = dummyHead;
while(prev.next != null){
if(prev.next.key.equals(key))
break;
prev = prev.next;
}
if(prev.next != null){
Node delNode = prev.next;
prev.next = delNode.next;
delNode.next = null;
size --;
return delNode.value;
}
return null;
}
测试代码 - 词频统计
public static void main(String[] args){
System.out.println("Pride and Prejudice");
ArrayList<String> words = new ArrayList<>();
if(FileOperation.readFile("pride-and-prejudice.txt", words)) {
System.out.println("Total words: " + words.size());
LinkedListMap<String, Integer> map = new LinkedListMap<>();
for (String word : words) {
if (map.contains(word))
map.set(word, map.get(word) + 1);
else
map.add(word, 1);
}
System.out.println("Total different words: " + map.getSize());
System.out.println("Frequency of PRIDE: " + map.get("pride"));
System.out.println("Frequency of PREJUDICE: " + map.get("prejudice"));
}
System.out.println();
}
输出:
- 基于链表的实现,很多操作都要遍历,所以速度很慢;
Pride and Prejudice
Total words: 125901
Total different words: 6530
Frequency of PRIDE: 53
Frequency of PREJUDICE: 11