一、创建链表节点
private class Node<K,V> implements Map.Entry<K,V>{
K key;
V val;
Node<K,V> next;
public Node(K key,V val){
this.key = key;
this.val = val;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return val;
}
@Override
public V setValue(V value) {
V oldValue = this.val;
this.val = value;
return oldValue;
}
}
思路:我们创建链表节点去实现Map.Entry<K,V>接口,这个接口是标准库里的,你只要实现这里面的方法就可以称之为Map.主要就是存储键值对,即K,V。
二、添加成员变量和构造方法
private final Node<K,V> head,tail;
private int size;
public ListMap(){
head = new Node(null,null);
tail = new Node(null,null);
head.next = tail;
this.size = 0;
}
思路:我们先创建头尾节点和size.在构造方法里我们将头尾节点初始化并头节点指针指向尾节点,size赋值0;
三、增/改
/***** 增/改 *****/
//在链表中添加key --> val键值对,如果键ket已存在,则将值改为val.
public V put(K key,V val){
if(key == null){
throw new NullPointerException("Key is null");
}
Node<K,V> p = getNode(key);
if(p!=null){
V oldValue = p.val;
p.val = val;
return oldValue;
}
Node<K,V> x = new Node<>(key,val);
x.next = head.next;
head.next = x;
size++;
return null;
}
private Node<K,V> getNode(K key){
for(Node p = head.next;p!=tail;p = p.next){
if(p.key.equals(key)){
return p;
}
}
return null;
}
思路:我们在写增逻辑时,其实是将增改放在一起的,我们先判断传入的key值是否为空,是否存在ListMap中,若存在就将原有的key节点修改val值,并将原来的val值返回,若不存在LsitMap中,咋们就创建一个节点接在头节点head后面(在链表里添加元素模块,我们必须找到前驱节点,head最好找到),最后将size++,别忘记了。
我们在判断key值存在Map中时,getNode方法就是遍历该Map,时间复杂度为O(n)。
四、删
/***** 删 *****/
public V remove(K key){
if(key == null){
throw new NullPointerException("key is null");
}
Node<K,V> prev = head;
for(Node<K,V> p = head.next;p != tail; p = p.next){
if(p.key.equals(key)){
//删除节点 p
prev.next = p.next;
size--;
return p.val;
}
//维护 p 节点的前驱节点
prev = p;
}
return null;
}
思路:一样,我们先判断传入得key是否为空。我们先遍历ListMap,找到key节点的前驱节点。我们都知道,删除一个链表节点需找到它的前驱节点,在这注意,初始化一个指向head的指针,当寻找要删除节点的指针p移动一位,prev就跟着移动一位,在prev还没移动前进行判断和操作,这时prev就成为了前驱节点指针。将prev节点指向p节点的下一个节点,这样就删除掉了节点p。记得size--.并返回删除节点的val值。
五、查
/***** 查 *****/
public V get(K key){
if(key == null){
throw new NullPointerException("key is null");
}
Node<K,V> p = getNode(key);
if(p==null){
return null;
}
return p.val;
}
public boolean containKey(K key){
if (key==null){
throw new NullPointerException("key is null");
}
return getNode(key)!=null;
}
思路:查的思路其实很简单,主要就时通过传入的key,然后通过遍历ListMap去找。
六、其他工具函数
public int size(){
return size;
}
public boolean isEmpty(){
return size==0;
}
public List<K> keys(){
LinkedList<K> keyList = new LinkedList<K>();
for(Node<K,V>p = head.next;p != tail; p = p.next){
keyList.addLast(p.key);
}
return keyList;
}
在keys方法里我们主要是将ListMap遍历取key值存入链表,全部打印出来。
总结:对Map映射、键值对具有初步认识,了解部分实现原理。为后续学习HashMap打好基础。