ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LRU的map+双链表实现(Go描述)

2021-05-21 16:34:32  阅读:195  来源: 互联网

标签:node map cache LRU key Go LinkedNode prev LRUCache


面云账户时候问了LRU,具体实现的方式是map+双链表。Set和Get的时间复杂度都是O(1)。完整写一遍复习一下, 仅作记录

/**
 * @Author: lzw5399
 * @Date: 2021/5/20 22:28
 * @Desc: 基于map和双链表实现的LRU算法
 */
package main

import "sync"

func main() {
	lru := NewLRUCache(3)

	lru.Set(1, 233)
	lru.Set(2, 666)
	lru.Set(3, 777)
	lru.Set(5, 888)

	lru.Get(2)
}

// LRUCache
type LRUCache struct {
	capacity int
	cache    map[int]*LinkedNode
	head     *LinkedNode
	tail     *LinkedNode
	sync.RWMutex
}

type LinkedNode struct {
	key, value int
	prev, next *LinkedNode
}

func NewLRUCache(capacity int) *LRUCache {
	return &LRUCache{
		capacity: capacity,
		cache:    make(map[int]*LinkedNode, capacity),
		head:     nil,
		tail:     nil,
		RWMutex:  sync.RWMutex{},
	}
}

// - key是否已存在
//   - 已存在, 将该节点移动到链表头部
//   - 未存在, 判断cap是否已满
//     - 满
//       - 移除链表尾的节点
//       - 新的node放入链表头
//       - 新的node放入cache的map中
//     - 未满
//       - 新的node放入链表头
//       - 新的node放入cache的map中
func (l *LRUCache) Set(key int, value int) {
	l.RLock()
	node, exist := l.cache[key]
	l.RUnlock()
	if exist {
		l.moveToHead(node)
		return
	}

	node = &LinkedNode{
		key:   key,
		value: value,
	}

	l.Lock()
	defer l.Unlock()

	if l.capacity == len(l.cache) {
		removedNode := l.removeTail()
		delete(l.cache, removedNode.key)
	}

	l.addToHead(node)
	l.cache[key] = node
}

// - 从map中获取是否存在
//   - 不存在
//     - 返回-1
//   - 存在
//     - 移到链表头部
//     - 并返回具体的值
func (l *LRUCache) Get(key int) int {
	l.RLock()
	node, exist := l.cache[key]
	l.RUnlock()
	if !exist {
		return -1
	}

	l.moveToHead(node)
	return node.value
}

func (l *LRUCache) moveToHead(node *LinkedNode) {
	l.removeNode(node)
	l.addToHead(node)
}

func (l *LRUCache) removeTail() *LinkedNode {
	return l.removeNode(l.tail)
}

func (l *LRUCache) removeNode(node *LinkedNode) *LinkedNode {
	// 头节点
	if node.prev == nil {
		l.head = node.next
		node.next.prev = nil
		return node
	}

	// 尾节点
	if node.next == nil {
		l.tail = node.prev
		node.prev.next = nil
		return node
	}

	// 中间节点
	node.prev.next = node.next
	node.next.prev = node.prev
	return node
}

func (l *LRUCache) addToHead(node *LinkedNode) {
	if l.head != nil {
		l.head.prev = node
	} else {
		l.tail = node
	}

	node.prev = nil
	node.next = l.head
	l.head = node
}

标签:node,map,cache,LRU,key,Go,LinkedNode,prev,LRUCache
来源: https://www.cnblogs.com/baoshu/p/14794330.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有