LinkedHashMap自制

本文介绍了如何使用Java实现LRU缓存数据结构,重点讲解了利用HashMap和双向链表实现的高效查找、插入和删除操作,以及与HashTable的区别。同时提及了HashTable的CRUD性能和冲突解决策略,以及Redis哨兵模式的基本概念。
摘要由CSDN通过智能技术生成

做的LC一道题,时间复杂度为O(1)的CRUD、数据结构,里面就想到了JAVA中的LinkedHashMap ,编码逻辑十分清楚。文字讲解放在了开头。

/**
 * @description: Leetcode_146 LRU缓存
 * 最近最少使用元素,查找插入修改时间复杂度都为O(1)。使用HashMap加上有序双向链表(即队列)的方式
 * 1、创建Node {key,value,prev,next,有参构造,无参构造}
 * 2、补充LRUCache构造方法,就是 初始化链表(head.next = tail; tail.prev = head;)
 * 3、补充put get方法,其中用到moveToHead,addToHead,removeTail等方法
 * 4、put: hashMap.get(key),如果没有就添加,创建node对象,addToHead方法添加,并hashmap.put(key),并判断添加完后链表大小是否大于容量,大于则removeTail
 * 5、get: hashMap.get(key),有就return得到的value,没有就是return -1
 *  6 7 8 朋友们自己多写几下,不要复制粘贴,链表的插入删除移动节点指针得动手练习(我就是动手写的,加强熟练度朋友们)。
 * 6、moveToHead: node.prev.next = node.next; node.next.prev = node.prev; node.prev = head; node.next = head.next; head.next.prev = node; head.next = node;
 * 7、addToHead: node.prev = head; node.next = head.next; head.next.prev = node; head.next = node;
 * 8、removeTail: tail.prev.prev.next = tail; tail.prev = tail.prev.prev;
 * @author: HammerRay
 * @date: 2024/3/22 下午8:35
 */

import java.util.HashMap;
import java.util.Map;
public class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;

        public DLinkedNode() {
        }

        public DLinkedNode(int _key, int _value) {
            key = _key;
            value = _value;
        }
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
    private int size;
    private int capacity;
    private DLinkedNode head, tail;

    public LRUCache(int capacity) {
        // hashMap + 队列(双向链表) 一层hash包一层双向链表
        this.size = 0;
        this.capacity = capacity;
        // 伪头部和伪尾部
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        // 如果key存在,想通过hashmap定位,再移动到头部  hashmap与hashtable的关系是 前者是线程不安全的,后者安全的
        moveToHead(node);
        return node.value;

    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            DLinkedNode newNode = new DLinkedNode(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                DLinkedNode tail = removeTail();
                cache.remove(tail.key);
                --size;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void moveToHead(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        node.prev = head;
        node.next = head.next;
        head.next = node;
        node.next.prev = node;
    }

    private DLinkedNode removeTail() {
        DLinkedNode result = tail.prev;
        tail.prev.prev.next = tail;
        tail.prev = tail.prev.prev;
        return result;
    }
}

其中回想起了一些知识点:

1、HashTable和HashMap的区别,前者是线程安全的,后者线程不安全,那些性能什么差异就是线程安不安全的差异,还有代码上的什么HashTable是实现了Map接口又继承了Dictionary类,HashMap只实现了Map接口,还有具备方法上的差异就不说了,因为个人认为不需要记住这些,感兴趣的朋友自行搜索一哈。

2、HashTable为什么能实现CRUD为零呢?主要是hash(key)函数,这个函数中,将key值转换为具体的数组上存储的位置index,并且函数中计算出来的数据十分散列,让每一个元素都随机分配到一个数组上。等到CRUD时候,比如get(key),通过hash(key)立马获得index,查找到元素。

3、HashTable中总会存在冲突有那些解决办法?

链地址法:hashtable的那个数组元素后,接有链表,发生冲突的元素往链表中添加

线性探测:从探测产生冲突位置向下一个一个位置地探测是否为空,有空位就向空位中插入。

二次探测: 通过计算一个二次方程来确定下一个探测的位置 ,有空就插

二重散列: 使用另一个hash()函数进行偏移量测量,寻找空位。

4、redis的哨兵模式是什么?

它是为了保证redis集群的高可用HA而产生的,通过配置配置文件调整哨兵的个数。哨兵节点会向主节点,发送ping,如果足够的哨兵发现,ping主节点异常,则集群开启调整,选取下一个主节点进行故障转移操作。

哇越往下想越多,redis的选主操作是如何进行的? 常见的选主算法有哪些?raft和paxos有什么异同?redis常用来做什么?为什么? etc.. 路漫漫其修远兮哟。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值