设计LRU缓存结构算法

LRU缓存结构算法的核心就是哈希表和双向链表的结合。

[要求]:

  1. set和get方法的时间复杂度为O(1)
  2. 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
  3. 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
  • 1.要保证set和get方法的时间复杂度为O(1),就是利用哈希表内存储的value实际上就是节点的地址,不用遍历取得。
  • 2/3.实际上就是优先级的问题,使用双向链表节点的相对顺序标识优先级,链表头部节点优先级最低,尾部优先级最高,所以每次对节点操作之后都会把节点移动到尾部,以保证优先级。

操作步骤:

1.构造Node节点,设置为泛型,方便用户。

public static class Node<K, V> {
		public K key;
		public V value;
		public Node last;
		public Node next;
		
		public Node(K key, V vaule) {
			this.key = key;
			this.value = vaule;
		}
	}

2.构建双向链表。

    //双向链表
	public static class NodeDoubleLinkedList<K, V> {
		private Node<K, V> head;
		private Node<K, V> tail;
		
		// 构造函数,设置 head,tail = null
		public NodeDoubleLinkedList() {
			this.head = null;
			this.tail = null;
		}
		
		// 加入Node节点到尾部
		public void NodeAdd(Node<K, V> newNode) {
			if (newNode == null) {
				return;
			}
			if (this.head == null) {
				this.head = newNode;
				this.tail = newNode;
			} else {
				this.tail.next = newNode;
				newNode.last = this.tail;
				this.tail = newNode;
			}
		}
		
		// 把节点移动到尾部,实际是把此节点的优先级调到最高
		public void moveNodeToTail(Node<K, V> node) {
			if (this.tail == null) {
				return;
			}
			if (this.head == node) {
				this.head = node.next;
				node.next.last = null;
			} else {
				node.last.next = node.next;
				node.next.last = node.last;
			}
			node.last = this.tail;
			node.next = null;
			this.tail.next = node;
			this.tail = node;
		}
		
		// 移除头部Node,实际是把优先级最低的节点移除
		public Node<K, V> removeHeadNode() {
			if (this.head == null) {
				return null;
			}
			Node<K, V> res = this.head;
			if (this.head == this.tail) {
				this.head = null;
				this.tail = null;
			} else {
				this.head = res.next;
				res.next = null;
				this.head.last = null;
			}
			return res;
		}
	}

3. 构造缓存功能

        // 缓存设置
		public static class MyCache<K, V> {
			private HashMap<K, Node<K, V>> keyNodeMap; 
			private NodeDoubleLinkedList<K, V> nodeList;
			private int capacity; // 记录优先级
			
			// 初始化优先级,哈希表,双向链表
			public MyCache(int capacity) {
				if (capacity < 1) {
					throw new RuntimeException("should be more than 0.");
				}
				this.keyNodeMap = new HashMap<K, Node<K, V>>();
				this.nodeList = new NodeDoubleLinkedList<K, V>();
				this.capacity = capacity;
			}
			
			// 得到节点内的值并且把此节点移动到链表最后(优先级调到最高)
			public V get(K key) {
				if (this.keyNodeMap.containsKey(key)) {
					Node<K, V> res = this.keyNodeMap.get(key);
					this.nodeList.moveNodeToTail(res);
					return res.value;
				}
				return null;
			}
			
			// 设置key,vaule. 
			public void set(K key, V value) {
				// 如果哈希表内包含了这个key,代表更新操作
				if (this.keyNodeMap.containsKey(key)) {
					Node<K, V> node = this.keyNodeMap.get(key);
					node.value = value;
					this.nodeList.moveNodeToTail(node);
				} else { // 新加记录
					Node<K, V> newNode = new Node<K, V>(key, value);
					this.keyNodeMap.put(key, newNode);
					this.nodeList.NodeAdd(newNode);
					if (this.keyNodeMap.size() == this.capacity + 1) {
						this.removeMostUnusedCache();
					}
				}
			}
			
			// 移除头部Node,移除哈希表内key
			private void removeMostUnusedCache() {
				Node<K, V> removeNode = this.nodeList.removeHeadNode();
				this.keyNodeMap.remove(removeNode.key);
			}
		}

4.主函数

public static void main(String[] args) {
        // 构造缓存最大值为3的缓存表
		MyCache<String, Integer> test = new MyCache<String, Integer>(3);
		test.set("a", 1);
		test.set("b", 2);
		System.out.println(test.get("a"));
	}

首次发文,不足之处请多多指点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值