美文网首页
LRU算法实现

LRU算法实现

作者: 梦想实现家_Z | 来源:发表于2021-03-19 14:11 被阅读0次
    package main
    
    import (
        "fmt"
    )
    
    // 定义节点结构体
    type node struct {
        key   string
        value string
        next  *node
        prev  *node
    }
    
    // 定义lru结构体
    type lru struct {
        //缓存最大数量
        k int
        // 存放节点数据
        cache map[string]*node
        //头节点
        head *node
        // 尾节点
        tail *node
    }
    
    // 工厂方法,构造一个LRU缓存对象
    func NewLRUCache(k int) *lru {
        return &lru{k: k}
    }
    
    // 对外开放的Get方法
    func (lru *lru) Get(key string) string {
        if lru.cache == nil {
            return ""
        }
        n, ok := lru.cache[key]
        if ok {
            value := n.value
            //更新到头节点
            lru.moveNodeToHead(n)
            return value
        } else {
            return ""
        }
    }
    
    // 对外开放的Set方法
    func (lru *lru) Set(key string, value string) {
        //初始化map
        if lru.cache == nil {
            lru.cache = make(map[string]*node)
        }
        n, ok := lru.cache[key]
        if ok {
            //更新缓存
            n.value = value
        } else {
            //创建新节点
            n = &node{key: key, value: value}
            // 添加到map中
            lru.cache[key] = n
            //如果超过缓存大小,移除最后一个节点
            if len(lru.cache) > lru.k {
                lru.removeTail()
            }
        }
        // 更新节点为头节点
        lru.moveNodeToHead(n)
    }
    
    //将指定节点移到头节点
    func (lru *lru) moveNodeToHead(n *node) {
        //如果头节点和尾节点都是空,说明是第一次添加数据
        if lru.head == nil && lru.tail == nil {
            lru.head = n
            lru.tail = n
            return
        }
        // 如果是头节点,那么不动
        if lru.head == n {
            return
        }
        nextNode := n.next
        prevNode := n.prev
        // 如果是尾节点,那么要先与上一个节点断开
        if n == lru.tail {
            prevNode.next = nil
            n.prev = nil
        } else if prevNode != nil && nextNode != nil {
            //如果是中间节点,要与前后节点都断开
            nextNode.prev = prevNode
            prevNode.next = nextNode
            n.prev = nil
        }
        //把节点移到到头节点
        n.next = lru.head
        lru.head.prev = n
        lru.head = n
    }
    
    //移除最后一个节点
    func (lru *lru) removeTail() {
        // 如果尾节点wei空,那么清空数据直接返回
        if lru.tail == nil {
            lru.cache = nil
            return
        }
        tailPrev := lru.tail.prev
        // 尾节点与上一个节点断开
        lru.tail.prev = nil
        if tailPrev != nil {
            tailPrev.next = nil
        }
        // 把上一个节点置为尾节点
        lru.tail = tailPrev
        // 从map中删除尾节点数据
        delete(lru.cache, lru.tail.key)
    }
    
    // 重写String方法,自定义打印结果
    func (lru *lru) String() string {
        point := lru.head
        result := ""
        flag := "\t"
        for point != nil {
            if len(result) > 0 {
                result = fmt.Sprintf("%v%v[%v:%v]", result, flag, point.key, point.value)
            } else {
                result = fmt.Sprintf("[%v:%v]", point.key, point.value)
            }
            point = point.next
        }
        return result
    }
    
    func main() {
        LRUCache := NewLRUCache(5)
        LRUCache.Set("1", "1")
        LRUCache.Set("2", "2")
        LRUCache.Set("3", "3")
        LRUCache.Set("4", "4")
        LRUCache.Set("5", "5")
        //打印缓存数据,验证容量是否起作用
        fmt.Println(LRUCache)
        //设置超过最大容量的数据
        LRUCache.Set("6", "6")
        //打印缓存数据,验证超过容量是否起作用
        fmt.Println(LRUCache)
        //查询头节点数据
        fmt.Println(LRUCache.Get("6"))
        //打印缓存数据
        fmt.Println(LRUCache)
        //查询非头节点数据
        fmt.Println(LRUCache.Get("4"))
        //打印缓存数据
        fmt.Println(LRUCache)
        //查询尾节点数据
        fmt.Println(LRUCache.Get("2"))
        //打印缓存数据
        fmt.Println(LRUCache)
    }
    
    image.png

    相关文章

      网友评论

          本文标题:LRU算法实现

          本文链接:https://www.haomeiwen.com/subject/mxbvcltx.html