LeetCode刷题笔记 146(涉及到LinkedHashMap)

题目:LDR缓冲机制
在这里插入图片描述
答案:
参考链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/

使用哈希表+双向链表

哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表。

定义链表头表示最近操作结点,链表尾表示最久没有访问的结点。每次进行get/put操作后,都把结点插入到链表头部。

首先写伪代码

// key 映射到 Node(key, val)
HashMap<Integer, Node> map;
// Node(k1, v1) <-> Node(k2, v2)...
DoubleList cache;

int get(int key) {
    if (key 不存在) {
        return -1;
    } else {        
        将数据 (key, val) 提到开头;
        return val;
    }
}

void put(int key, int val) {
    Node x = new Node(key, val);
    if (key 已存在) {
        把旧的数据删除;
        将新节点 x 插入到开头;
    } else {
        if (cache 已满) {
            删除链表的最后一个数据腾位置;
            删除 map 中映射到该数据的键;
        } 
        将新节点 x 插入到开头;
        map 中新建 key 对新节点 x 的映射;
    }
}
import java.util.Hashtable;
class LRUCache {

  class DLinkedNode {  //双链表结点
    int key,value;
    DLinkedNode prev,next;
    public DLinkedNode(int k, int v) {
        this.key = k;
        this.value = v;
    }
  }

  private void addNode(DLinkedNode node) { //在链表头部添加结点
    node.prev = head;
    node.next = head.next;

    head.next.prev = node;
    head.next = node;
  }

  private void removeNode(DLinkedNode node){ //删除某结点
    node.prev.next = node.next;
    node.next.prev = node.prev;
  }

  private void moveToHead(DLinkedNode node){  //删除某结点并插入到开头
    removeNode(node);
    addNode(node);
  }

  private DLinkedNode popTail() { // 删除链表中最后一个节点,并返回该节点
    DLinkedNode res = tail.prev;
    removeNode(res);
    return res;
  }

  private Hashtable<Integer, DLinkedNode> cache =
          new Hashtable<Integer, DLinkedNode>();
  private int size;
  private int capacity;
  private DLinkedNode head, tail;  //头尾虚节点

  public LRUCache(int capacity) {
    this.size = 0;
    this.capacity = capacity;

    head = new DLinkedNode(0,0);
    tail = new DLinkedNode(0,0);

    head.next = tail;
    tail.prev = head;
  }

  public int get(int key) {
    DLinkedNode node = cache.get(key);
    if (node == null) return -1;
    moveToHead(node);
    return node.value;
  }

  public void put(int key, int value) {
    DLinkedNode node = cache.get(key);

    if(node == null) { //key不存在
      DLinkedNode newNode = new DLinkedNode(key,value);
      cache.put(key, newNode);
      addNode(newNode);

      ++size;
      if(size > capacity) {
        DLinkedNode tail = popTail();
        cache.remove(tail.key);
        --size;
      }
    } else { //key存在
      node.value = value;
      moveToHead(node);
    }
  }
}


/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

积累:
LinkedHashMap是HashMap的子类,LinkedHashMap 是有序的,因为 LinkedHashMap 在 HashMap 的基础上单独维护了一个具有所有数据的双向链表,该链表保证了元素迭代的顺序。

LinkedHashMap支持两种顺序插入顺序 、 访问顺序
(1)插入顺序:先添加的在前面,后添加的在后面。修改操作不影响顺序
(2)访问顺序:所谓访问指的是get/put操作,对一个键执行get/put操作后,其对应的键值对会移动到链表末尾,所以最末尾的是最近访问的,最开始的是最久没有被访问的,这就是访问顺序。

构造函数有三个参数

public LinkedHashMap(int initialCapacity, //初始容量(默认16)
                     float loadFactor,    //加载因子(0.75)
                     boolean accessOrder) //指定LinkedHashMap的迭代顺序,true表示按照访问顺序,false表示插入顺序,默认false
{ 
     super(initialCapacity, loadFactor);
     this.accessOrder = accessOrder;
}

在LinkedHashMap添加元素后,会调用removeEldestEntry防范,传递的参数是最久没有被访问的键值对,如果方法返回true,这个最久的键值对就会被删除。LinkedHashMap中的实现总返回false,该子类重写后即可实现对容量的控制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值