映射 01 基于链表的映射

本文详细介绍了一种基于链表实现的Map数据结构,包括其基本操作如添加、删除、查找等的实现原理及代码示例。通过具体案例,如词频统计的应用,展示了链表Map的实际效能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

映射(字典) - 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值