import "sync"
type Node struct {
key, value int
prev, next *Node
}
type LRUCache struct {
mu sync.RWMutex
capacity int
cache map[int]*Node
head *Node
tail *Node
}
func NewLRUCache(capacity int) *LRUCache {
lru := &LRUCache{
capacity: capacity,
cache: make(map[int]*Node),
head: &Node{},
tail: &Node{},
}
lru.head.next = lru.tail
lru.tail.prev = lru.head
return lru
}
func (lru *LRUCache) Get(key int) int {
lru.mu.Lock()
defer lru.mu.Unlock()
if node, ok := lru.cache[key]; ok {
lru.moveToHead(node)
return node.value
}
return -1
}
func (lru *LRUCache) Put(key, value int) {
lru.mu.Lock()
defer lru.mu.Unlock()
if node, ok := lru.cache[key]; ok {
node.value = value
lru.moveToHead(node)
return
}
node := &Node{key: key, value: value}
lru.cache[key] = node
lru.addToHead(node)
if len(lru.cache) > lru.capacity {
removed := lru.removeTail()
delete(lru.cache, removed.key)
}
}
func (lru *LRUCache) moveToHead(node *Node) {
lru.removeNode(node)
lru.addToHead(node)
}
func (lru *LRUCache) removeNode(node *Node) {
node.prev.next = node.next
node.next.prev = node.prev
}
func (lru *LRUCache) addToHead(node *Node) {
node.prev = lru.head
node.next = lru.head.next
lru.head.next.prev = node
lru.head.next = node
}
func (lru *LRUCache) removeTail() *Node {
node := lru.tail.prev
lru.removeNode(node)
return node
}时间复杂度:O(1)
空间复杂度:O(capacity)
多层链表结构,通过"跳跃"加速查找:
Level 3: 1 ----------> 7 ----------> 19
Level 2: 1 ------> 4 -> 7 -> 10 --> 19
Level 1: 1 -> 2 -> 4 -> 7 -> 10 -> 13 -> 19
Level 0: 1 -> 2 -> 3 -> 4 -> 7 -> 10 -> 13 -> 16 -> 19
import (
"math/rand"
)
const MaxLevel = 16
type SkipListNode struct {
key int
value interface{}
forward []*SkipListNode
}
type SkipList struct {
header *SkipListNode
level int
}
func NewSkipList() *SkipList {
return &SkipList{
header: &SkipListNode{forward: make([]*SkipListNode, MaxLevel)},
level: 1,
}
}
func (sl *SkipList) randomLevel() int {
level := 1
for rand.Float32() < 0.5 && level < MaxLevel {
level++
}
return level
}
func (sl *SkipList) Insert(key int, value interface{}) {
update := make([]*SkipListNode, MaxLevel)
current := sl.header
// 查找插入位置
for i := sl.level - 1; i >= 0; i-- {
for current.forward[i] != nil && current.forward[i].key < key {
current = current.forward[i]
}
update[i] = current
}
// 创建新节点
level := sl.randomLevel()
if level > sl.level {
for i := sl.level; i < level; i++ {
update[i] = sl.header
}
sl.level = level
}
newNode := &SkipListNode{
key: key,
value: value,
forward: make([]*SkipListNode, level),
}
// 插入节点
for i := 0; i < level; i++ {
newNode.forward[i] = update[i].forward[i]
update[i].forward[i] = newNode
}
}
func (sl *SkipList) Search(key int) interface{} {
current := sl.header
for i := sl.level - 1; i >= 0; i-- {
for current.forward[i] != nil && current.forward[i].key < key {
current = current.forward[i]
}
}
current = current.forward[0]
if current != nil && current.key == key {
return current.value
}
return nil
}时间复杂度:平均O(log n)
应用:Redis的有序集合(Sorted Set)
- 所有数据存储在叶子节点
- 叶子节点形成有序链表
- 非叶子节点只存索引
- MySQL索引
- 文件系统索引
优势:
- 树高低(3-4层支持千万级数据)
- 范围查询高效
- 磁盘IO次数少
通过多个哈希函数判断元素是否存在:
- 不存在:一定不存在
- 存在:可能存在(有误判率)
import "hash/fnv"
type BloomFilter struct {
bits []bool
size int
hashes int
}
func NewBloomFilter(size, hashes int) *BloomFilter {
return &BloomFilter{
bits: make([]bool, size),
size: size,
hashes: hashes,
}
}
func (bf *BloomFilter) Add(item string) {
for i := 0; i < bf.hashes; i++ {
hash := bf.hash(item, i)
bf.bits[hash%uint32(bf.size)] = true
}
}
func (bf *BloomFilter) Contains(item string) bool {
for i := 0; i < bf.hashes; i++ {
hash := bf.hash(item, i)
if !bf.bits[hash%uint32(bf.size)] {
return false
}
}
return true
}
func (bf *BloomFilter) hash(item string, seed int) uint32 {
h := fnv.New32a()
h.Write([]byte(item))
h.Write([]byte{byte(seed)})
return h.Sum32()
}- 缓存穿透防护
- 网页URL去重
- 垃圾邮件过滤
关键要点:
- ✅ LRU Cache:O(1)读写,双向链表+哈希表
- ✅ 跳表:多层链表,Redis有序集合的实现
- ✅ B+树:MySQL索引,树高低,范围查询高效
- ✅ 布隆过滤器:空间高效,允许误判
💡 思考题:
- 为什么MySQL使用B+树而不是B树?
- 跳表的层数如何确定?
- 如何降低布隆过滤器的误判率?