美文网首页
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