Skip to content

Commit

Permalink
add 20_lru.go file
Browse files Browse the repository at this point in the history
  • Loading branch information
lixingliang committed Mar 1, 2019
1 parent bc649e3 commit 1a16bc2
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 0 deletions.
148 changes: 148 additions & 0 deletions go/20_lru/lru_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package lru_cache

const (
hostbit = uint64(^uint(0)) == ^uint64(0)
LENGTH = 100
)

type lruNode struct {
prev *lruNode
next *lruNode

key int // lru key
value int // lru value

hnext *lruNode // 拉链
}

type LRUCache struct {
node []lruNode // hash list

head *lruNode // lru head node
tail *lruNode // lru tail node

capacity int //
used int //
}

func Constructor(capacity int) LRUCache {
return LRUCache{
node: make([]lruNode, LENGTH),
head: nil,
tail: nil,
capacity: capacity,
used: 0,
}
}

func (this *LRUCache) Get(key int) int {
if this.tail == nil {
return -1
}

if tmp := this.searchNode(key); tmp != nil {
this.moveToTail(tmp)
return tmp.value
}
return -1
}

func (this *LRUCache) Put(key int, value int) {
// 1. 首次插入数据
// 2. 插入数据不在 LRU 中
// 3. 插入数据在 LRU 中
// 4. 插入数据不在 LRU 中, 并且 LRU 已满

if tmp := this.searchNode(key); tmp != nil {
tmp.value = value
this.moveToTail(tmp)
return
}
this.addNode(key, value)

if this.used > this.capacity {
this.delNode()
}
}

func (this *LRUCache) addNode(key int, value int) {
newNode := &lruNode{
key: key,
value: value,
}

tmp := &this.node[hash(key)]
newNode.hnext = tmp.hnext
tmp.hnext = newNode
this.used++

if this.tail == nil {
this.tail, this.head = newNode, newNode
return
}
this.tail.next = newNode
newNode.prev = this.tail
this.tail = newNode
}

func (this *LRUCache) delNode() {
if this.head == nil {
return
}
prev := &this.node[hash(this.head.key)]
tmp := prev.hnext

for tmp != nil && tmp.key != this.head.key {
prev = tmp
tmp = tmp.hnext
}
if tmp == nil {
return
}
prev.hnext = tmp.hnext
this.head = this.head.next
this.head.prev = nil
this.used--
}

func (this *LRUCache) searchNode(key int) *lruNode {
if this.tail == nil {
return nil
}

// 查找
tmp := this.node[hash(key)].hnext
for tmp != nil {
if tmp.key == key {
return tmp
}
tmp = tmp.hnext
}
return nil
}

func (this *LRUCache) moveToTail(node *lruNode) {
if this.tail == node {
return
}
if this.head == node {
this.head = node.next
this.head.prev = nil
} else {
node.next.prev = node.prev
node.prev.next = node.next
}

node.next = nil
this.tail.next = node
node.prev = this.tail

this.tail = node
}

func hash(key int) int {
if hostbit {
return (key ^ (key >> 32)) & (LENGTH - 1)
}
return (key ^ (key >> 16)) & (LENGTH - 1)
}
67 changes: 67 additions & 0 deletions go/20_lru/lru_cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package lru_cache

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_Hostbit(t *testing.T) {
fmt.Println(hostbit)
}

func Test_LRU(t *testing.T) {
lru := Constructor(2)

lru.Put(1, 1)
lru.Put(2, 2)
assert.Equal(t, lru.Get(1), 1) // returns 1
lru.Put(3, 3) // evicts key 2
assert.Equal(t, lru.Get(2), -1) // returns -1 (not found)
lru.Put(4, 4) // evicts key 1
assert.Equal(t, lru.Get(1), -1) // returns -1 (not found)
assert.Equal(t, lru.Get(3), 3) // returns 3
assert.Equal(t, lru.Get(4), 4) // returns 4
}

func Test_LRU_PutGet(t *testing.T) {
lru := Constructor(1)

lru.Put(1, 2)
assert.Equal(t, lru.Get(1), 2) // returns 2
}

func Test_LRU_PutGetPutGetGet(t *testing.T) {
lru := Constructor(1)

lru.Put(2, 1)
assert.Equal(t, lru.Get(2), 1) // returns 1
lru.Put(3, 2)
assert.Equal(t, lru.Get(2), -1) // returns -1
assert.Equal(t, lru.Get(3), 2) // returns 2
}

func Test_LRU_PPGPPG(t *testing.T) {
lru := Constructor(2)

lru.Put(2, 1)
lru.Put(2, 2)
assert.Equal(t, lru.Get(2), 2) // returns 2
lru.Put(1, 4)
lru.Put(4, 1)
assert.Equal(t, lru.Get(2), -1) // returns -1
assert.Equal(t, lru.Get(3), -1) // returns -1
}

func Test_LRU_PPGPPG_2(t *testing.T) {
lru := Constructor(2)

lru.Put(2, 1)
lru.Put(2, 2)
assert.Equal(t, lru.Get(2), 2) // returns 2
lru.Put(1, 1)
lru.Put(4, 1)
assert.Equal(t, lru.Get(2), -1) // returns -1
assert.Equal(t, lru.Get(3), -1) // returns -1
}

0 comments on commit 1a16bc2

Please sign in to comment.