HiHuo
首页
博客
手册
工具
首页
博客
手册
工具
  • 学习 Redis

    • Redis 手写实现学习指南
    • 快速开始
    • Redis 架构总览与线程模型
    • RESP 协议与网络通信
    • 事件循环与 I/O 多路复用
    • 底层数据结构设计
    • 字符串与 SDS 实现
    • 哈希表与字典实现
    • 列表与跳表实现
    • 有序集合实现
    • 内存管理与对象系统
    • RDB 持久化机制
    • AOF 持久化机制
    • 混合持久化策略
    • 分布式锁实现
    • 缓存一致性策略
    • 主从复制机制
    • 哨兵模式实现
    • 内存优化与 GC 调优

列表与跳表实现

学习目标

  • 深入理解双向链表的实现和优化技巧
  • 掌握跳跃表的原理和概率分析
  • 实现完整的跳表插入、删除、查找算法
  • 理解 quicklist 的设计思想和实现
  • 对比分析跳表与平衡树的性能差异

双向链表实现

1. 链表结构设计

双向链表是 Redis 列表的基础数据结构,支持 O(1) 的头部和尾部操作:

// list/doubly_linked_list.go
package list

import (
    "fmt"
    "sync"
)

// 链表节点
type ListNode struct {
    value interface{}
    prev  *ListNode
    next  *ListNode
}

// 双向链表
type DoublyLinkedList struct {
    head   *ListNode
    tail   *ListNode
    length int
    mu     sync.RWMutex
}

// 创建新链表
func NewDoublyLinkedList() *DoublyLinkedList {
    return &DoublyLinkedList{
        head:   nil,
        tail:   nil,
        length: 0,
    }
}

// 创建新节点
func newNode(value interface{}) *ListNode {
    return &ListNode{
        value: value,
        prev:  nil,
        next:  nil,
    }
}

2. 基础操作实现

// list/basic_operations.go
package list

// 在头部插入
func (dll *DoublyLinkedList) PushFront(value interface{}) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    newNode := newNode(value)
    
    if dll.head == nil {
        // 空链表
        dll.head = newNode
        dll.tail = newNode
    } else {
        // 非空链表
        newNode.next = dll.head
        dll.head.prev = newNode
        dll.head = newNode
    }
    
    dll.length++
}

// 在尾部插入
func (dll *DoublyLinkedList) PushBack(value interface{}) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    newNode := newNode(value)
    
    if dll.tail == nil {
        // 空链表
        dll.head = newNode
        dll.tail = newNode
    } else {
        // 非空链表
        newNode.prev = dll.tail
        dll.tail.next = newNode
        dll.tail = newNode
    }
    
    dll.length++
}

// 在指定位置插入
func (dll *DoublyLinkedList) Insert(index int, value interface{}) error {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if index < 0 || index > dll.length {
        return fmt.Errorf("index out of range")
    }
    
    if index == 0 {
        dll.PushFront(value)
        return nil
    }
    
    if index == dll.length {
        dll.PushBack(value)
        return nil
    }
    
    // 找到插入位置
    current := dll.head
    for i := 0; i < index; i++ {
        current = current.next
    }
    
    // 创建新节点
    newNode := newNode(value)
    newNode.prev = current.prev
    newNode.next = current
    current.prev.next = newNode
    current.prev = newNode
    
    dll.length++
    return nil
}

// 从头部弹出
func (dll *DoublyLinkedList) PopFront() (interface{}, error) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if dll.head == nil {
        return nil, fmt.Errorf("list is empty")
    }
    
    value := dll.head.value
    
    if dll.head == dll.tail {
        // 只有一个节点
        dll.head = nil
        dll.tail = nil
    } else {
        // 多个节点
        dll.head = dll.head.next
        dll.head.prev = nil
    }
    
    dll.length--
    return value, nil
}

// 从尾部弹出
func (dll *DoublyLinkedList) PopBack() (interface{}, error) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if dll.tail == nil {
        return nil, fmt.Errorf("list is empty")
    }
    
    value := dll.tail.value
    
    if dll.head == dll.tail {
        // 只有一个节点
        dll.head = nil
        dll.tail = nil
    } else {
        // 多个节点
        dll.tail = dll.tail.prev
        dll.tail.next = nil
    }
    
    dll.length--
    return value, nil
}

// 删除指定位置的元素
func (dll *DoublyLinkedList) Remove(index int) (interface{}, error) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if index < 0 || index >= dll.length {
        return nil, fmt.Errorf("index out of range")
    }
    
    if index == 0 {
        return dll.PopFront()
    }
    
    if index == dll.length-1 {
        return dll.PopBack()
    }
    
    // 找到要删除的节点
    current := dll.head
    for i := 0; i < index; i++ {
        current = current.next
    }
    
    // 删除节点
    current.prev.next = current.next
    current.next.prev = current.prev
    
    dll.length--
    return current.value, nil
}

// 获取指定位置的元素
func (dll *DoublyLinkedList) Get(index int) (interface{}, error) {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    
    if index < 0 || index >= dll.length {
        return nil, fmt.Errorf("index out of range")
    }
    
    // 优化:从头部或尾部开始遍历
    if index < dll.length/2 {
        // 从头部开始
        current := dll.head
        for i := 0; i < index; i++ {
            current = current.next
        }
        return current.value, nil
    } else {
        // 从尾部开始
        current := dll.tail
        for i := dll.length - 1; i > index; i-- {
            current = current.prev
        }
        return current.value, nil
    }
}

// 设置指定位置的元素
func (dll *DoublyLinkedList) Set(index int, value interface{}) error {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if index < 0 || index >= dll.length {
        return fmt.Errorf("index out of range")
    }
    
    // 找到节点
    current := dll.head
    for i := 0; i < index; i++ {
        current = current.next
    }
    
    current.value = value
    return nil
}

// 获取链表长度
func (dll *DoublyLinkedList) Length() int {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    return dll.length
}

// 检查是否为空
func (dll *DoublyLinkedList) IsEmpty() bool {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    return dll.length == 0
}

// 清空链表
func (dll *DoublyLinkedList) Clear() {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    dll.head = nil
    dll.tail = nil
    dll.length = 0
}

3. 高级操作实现

// list/advanced_operations.go
package list

// 查找元素
func (dll *DoublyLinkedList) Find(value interface{}) int {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    
    current := dll.head
    index := 0
    
    for current != nil {
        if current.value == value {
            return index
        }
        current = current.next
        index++
    }
    
    return -1
}

// 查找所有匹配的元素
func (dll *DoublyLinkedList) FindAll(value interface{}) []int {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    
    var indices []int
    current := dll.head
    index := 0
    
    for current != nil {
        if current.value == value {
            indices = append(indices, index)
        }
        current = current.next
        index++
    }
    
    return indices
}

// 删除所有匹配的元素
func (dll *DoublyLinkedList) RemoveAll(value interface{}) int {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    count := 0
    current := dll.head
    
    for current != nil {
        next := current.next
        
        if current.value == value {
            // 删除当前节点
            if current.prev == nil {
                // 头部节点
                dll.head = current.next
                if dll.head != nil {
                    dll.head.prev = nil
                }
            } else {
                current.prev.next = current.next
            }
            
            if current.next == nil {
                // 尾部节点
                dll.tail = current.prev
                if dll.tail != nil {
                    dll.tail.next = nil
                }
            } else {
                current.next.prev = current.prev
            }
            
            dll.length--
            count++
        }
        
        current = next
    }
    
    return count
}

// 反转链表
func (dll *DoublyLinkedList) Reverse() {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    current := dll.head
    var prev *ListNode
    
    for current != nil {
        next := current.next
        current.next = prev
        current.prev = next
        prev = current
        current = next
    }
    
    // 交换头部和尾部
    dll.head, dll.tail = dll.tail, dll.head
}

// 获取子链表
func (dll *DoublyLinkedList) SubList(start, end int) (*DoublyLinkedList, error) {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    
    if start < 0 || end > dll.length || start > end {
        return nil, fmt.Errorf("invalid range")
    }
    
    subList := NewDoublyLinkedList()
    current := dll.head
    
    // 移动到起始位置
    for i := 0; i < start; i++ {
        current = current.next
    }
    
    // 复制元素
    for i := start; i < end; i++ {
        subList.PushBack(current.value)
        current = current.next
    }
    
    return subList, nil
}

// 合并两个链表
func (dll *DoublyLinkedList) Merge(other *DoublyLinkedList) {
    dll.mu.Lock()
    defer dll.mu.Unlock()
    
    if other.head == nil {
        return
    }
    
    if dll.head == nil {
        dll.head = other.head
        dll.tail = other.tail
        dll.length = other.length
    } else {
        dll.tail.next = other.head
        other.head.prev = dll.tail
        dll.tail = other.tail
        dll.length += other.length
    }
    
    // 清空另一个链表
    other.head = nil
    other.tail = nil
    other.length = 0
}

// 转换为切片
func (dll *DoublyLinkedList) ToSlice() []interface{} {
    dll.mu.RLock()
    defer dll.mu.RUnlock()
    
    result := make([]interface{}, dll.length)
    current := dll.head
    index := 0
    
    for current != nil {
        result[index] = current.value
        current = current.next
        index++
    }
    
    return result
}

// 从切片创建链表
func NewDoublyLinkedListFromSlice(slice []interface{}) *DoublyLinkedList {
    dll := NewDoublyLinkedList()
    
    for _, value := range slice {
        dll.PushBack(value)
    }
    
    return dll
}

跳跃表实现

1. 跳表结构设计

跳跃表是一种概率数据结构,通过多层链表实现 O(log n) 的查找、插入和删除操作:

// skiplist/skiplist.go
package skiplist

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

// 跳表节点
type SkipListNode struct {
    key     interface{}
    value   interface{}
    score   float64
    level   int
    forward []*SkipListNode
}

// 跳跃表
type SkipList struct {
    header   *SkipListNode
    tail     *SkipListNode
    length   int
    level    int
    maxLevel int
    mu       sync.RWMutex
}

// 创建新节点
func newNode(key, value interface{}, score float64, level int) *SkipListNode {
    return &SkipListNode{
        key:     key,
        value:   value,
        score:   score,
        level:   level,
        forward: make([]*SkipListNode, level+1),
    }
}

// 创建跳跃表
func NewSkipList(maxLevel int) *SkipList {
    if maxLevel <= 0 {
        maxLevel = 16
    }
    
    // 创建头节点
    header := newNode(nil, nil, 0, maxLevel)
    
    return &SkipList{
        header:   header,
        tail:     nil,
        length:   0,
        level:    0,
        maxLevel: maxLevel,
    }
}

// 随机生成层数
func (sl *SkipList) randomLevel() int {
    level := 0
    for rand.Float64() < 0.5 && level < sl.maxLevel {
        level++
    }
    return level
}

2. 查找操作实现

// skiplist/search.go
package skiplist

// 查找节点
func (sl *SkipList) Search(key interface{}) (interface{}, bool) {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    node := sl.searchNode(key)
    if node != nil {
        return node.value, true
    }
    
    return nil, false
}

// 查找节点(内部方法)
func (sl *SkipList) searchNode(key interface{}) *SkipListNode {
    current := sl.header
    
    // 从最高层开始搜索
    for i := sl.level; i >= 0; i-- {
        // 在当前层向前搜索
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, key) < 0 {
            current = current.forward[i]
        }
    }
    
    // 移动到下一个节点
    current = current.forward[0]
    
    // 检查是否找到
    if current != nil && sl.compare(current.key, key) == 0 {
        return current
    }
    
    return nil
}

// 比较函数
func (sl *SkipList) compare(key1, key2 interface{}) int {
    switch k1 := key1.(type) {
    case string:
        if k2, ok := key2.(string); ok {
            if k1 < k2 {
                return -1
            } else if k1 > k2 {
                return 1
            }
            return 0
        }
    case int:
        if k2, ok := key2.(int); ok {
            if k1 < k2 {
                return -1
            } else if k1 > k2 {
                return 1
            }
            return 0
        }
    case float64:
        if k2, ok := key2.(float64); ok {
            if k1 < k2 {
                return -1
            } else if k1 > k2 {
                return 1
            }
            return 0
        }
    }
    
    // 默认字符串比较
    s1 := fmt.Sprintf("%v", key1)
    s2 := fmt.Sprintf("%v", key2)
    if s1 < s2 {
        return -1
    } else if s1 > s2 {
        return 1
    }
    return 0
}

// 查找范围
func (sl *SkipList) SearchRange(start, end interface{}) []interface{} {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    var result []interface{}
    current := sl.findFirst(start)
    
    for current != nil && sl.compare(current.key, end) <= 0 {
        result = append(result, current.value)
        current = current.forward[0]
    }
    
    return result
}

// 查找第一个大于等于指定键的节点
func (sl *SkipList) findFirst(key interface{}) *SkipListNode {
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, key) < 0 {
            current = current.forward[i]
        }
    }
    
    return current.forward[0]
}

3. 插入操作实现

// skiplist/insert.go
package skiplist

// 插入节点
func (sl *SkipList) Insert(key, value interface{}) error {
    sl.mu.Lock()
    defer sl.mu.Unlock()
    
    // 查找插入位置
    update := make([]*SkipListNode, sl.maxLevel+1)
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, key) < 0 {
            current = current.forward[i]
        }
        update[i] = current
    }
    
    current = current.forward[0]
    
    // 如果键已存在,更新值
    if current != nil && sl.compare(current.key, key) == 0 {
        current.value = value
        return nil
    }
    
    // 生成随机层数
    level := sl.randomLevel()
    
    // 如果新层数大于当前层数,更新头节点
    if level > sl.level {
        for i := sl.level + 1; i <= level; i++ {
            update[i] = sl.header
        }
        sl.level = level
    }
    
    // 创建新节点
    newNode := newNode(key, value, 0, level)
    
    // 插入节点
    for i := 0; i <= level; i++ {
        newNode.forward[i] = update[i].forward[i]
        update[i].forward[i] = newNode
    }
    
    // 更新尾节点
    if newNode.forward[0] == nil {
        sl.tail = newNode
    }
    
    sl.length++
    return nil
}

// 插入带分数的节点
func (sl *SkipList) InsertWithScore(key, value interface{}, score float64) error {
    sl.mu.Lock()
    defer sl.mu.Unlock()
    
    // 查找插入位置
    update := make([]*SkipListNode, sl.maxLevel+1)
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            (current.forward[i].score < score || 
             (current.forward[i].score == score && 
              sl.compare(current.forward[i].key, key) < 0)) {
            current = current.forward[i]
        }
        update[i] = current
    }
    
    current = current.forward[0]
    
    // 如果键已存在,更新值
    if current != nil && sl.compare(current.key, key) == 0 {
        current.value = value
        current.score = score
        return nil
    }
    
    // 生成随机层数
    level := sl.randomLevel()
    
    // 如果新层数大于当前层数,更新头节点
    if level > sl.level {
        for i := sl.level + 1; i <= level; i++ {
            update[i] = sl.header
        }
        sl.level = level
    }
    
    // 创建新节点
    newNode := newNode(key, value, score, level)
    
    // 插入节点
    for i := 0; i <= level; i++ {
        newNode.forward[i] = update[i].forward[i]
        update[i].forward[i] = newNode
    }
    
    // 更新尾节点
    if newNode.forward[0] == nil {
        sl.tail = newNode
    }
    
    sl.length++
    return nil
}

4. 删除操作实现

// skiplist/delete.go
package skiplist

// 删除节点
func (sl *SkipList) Delete(key interface{}) bool {
    sl.mu.Lock()
    defer sl.mu.Unlock()
    
    // 查找删除位置
    update := make([]*SkipListNode, sl.maxLevel+1)
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, key) < 0 {
            current = current.forward[i]
        }
        update[i] = current
    }
    
    current = current.forward[0]
    
    // 如果找到节点,删除它
    if current != nil && sl.compare(current.key, key) == 0 {
        // 更新前驱节点的指针
        for i := 0; i <= current.level; i++ {
            update[i].forward[i] = current.forward[i]
        }
        
        // 更新尾节点
        if current == sl.tail {
            if current.level > 0 {
                sl.tail = update[0]
            } else {
                sl.tail = nil
            }
        }
        
        // 更新层数
        for sl.level > 0 && sl.header.forward[sl.level] == nil {
            sl.level--
        }
        
        sl.length--
        return true
    }
    
    return false
}

// 删除范围
func (sl *SkipList) DeleteRange(start, end interface{}) int {
    sl.mu.Lock()
    defer sl.mu.Unlock()
    
    count := 0
    current := sl.findFirst(start)
    
    for current != nil && sl.compare(current.key, end) <= 0 {
        next := current.forward[0]
        sl.deleteNode(current)
        current = next
        count++
    }
    
    return count
}

// 删除节点(内部方法)
func (sl *SkipList) deleteNode(node *SkipListNode) {
    // 查找前驱节点
    update := make([]*SkipListNode, sl.maxLevel+1)
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, node.key) < 0 {
            current = current.forward[i]
        }
        update[i] = current
    }
    
    // 更新前驱节点的指针
    for i := 0; i <= node.level; i++ {
        update[i].forward[i] = node.forward[i]
    }
    
    // 更新尾节点
    if node == sl.tail {
        if node.level > 0 {
            sl.tail = update[0]
        } else {
            sl.tail = nil
        }
    }
    
    // 更新层数
    for sl.level > 0 && sl.header.forward[sl.level] == nil {
        sl.level--
    }
    
    sl.length--
}

5. 范围查询实现

// skiplist/range.go
package skiplist

// 获取排名
func (sl *SkipList) GetRank(key interface{}) int {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    rank := 0
    current := sl.header
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            sl.compare(current.forward[i].key, key) < 0 {
            rank += (1 << i)
            current = current.forward[i]
        }
    }
    
    current = current.forward[0]
    if current != nil && sl.compare(current.key, key) == 0 {
        return rank
    }
    
    return -1
}

// 根据排名获取节点
func (sl *SkipList) GetByRank(rank int) (interface{}, bool) {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    if rank < 0 || rank >= sl.length {
        return nil, false
    }
    
    current := sl.header
    currentRank := 0
    
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            currentRank+(1<<i) <= rank {
            currentRank += (1 << i)
            current = current.forward[i]
        }
    }
    
    return current.value, true
}

// 获取范围排名
func (sl *SkipList) GetRangeByRank(start, end int) []interface{} {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    if start < 0 || end >= sl.length || start > end {
        return nil
    }
    
    var result []interface{}
    current := sl.header
    currentRank := 0
    
    // 移动到起始位置
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            currentRank+(1<<i) <= start {
            currentRank += (1 << i)
            current = current.forward[i]
        }
    }
    
    // 收集范围内的节点
    for i := start; i <= end; i++ {
        if current != nil {
            result = append(result, current.value)
            current = current.forward[0]
        }
    }
    
    return result
}

// 获取分数范围
func (sl *SkipList) GetRangeByScore(minScore, maxScore float64) []interface{} {
    sl.mu.RLock()
    defer sl.mu.RUnlock()
    
    var result []interface{}
    current := sl.header
    
    // 移动到起始位置
    for i := sl.level; i >= 0; i-- {
        for current.forward[i] != nil && 
            current.forward[i].score < minScore {
            current = current.forward[i]
        }
    }
    
    // 收集范围内的节点
    current = current.forward[0]
    for current != nil && current.score <= maxScore {
        result = append(result, current.value)
        current = current.forward[0]
    }
    
    return result
}

QuickList 实现

1. QuickList 结构设计

QuickList 是 Redis 3.2 引入的列表实现,结合了双向链表和压缩列表的优点:

// quicklist/quicklist.go
package quicklist

import (
    "fmt"
    "sync"
)

// 压缩列表节点
type ZipListNode struct {
    data []byte
    len  int
}

// 压缩列表
type ZipList struct {
    data   []byte
    length int
    tail   int
}

// QuickList 节点
type QuickListNode struct {
    prev *QuickListNode
    next *QuickListNode
    zl   *ZipList
    size int
}

// QuickList
type QuickList struct {
    head   *QuickListNode
    tail   *QuickListNode
    length int
    count  int
    mu     sync.RWMutex
}

// 创建 QuickList
func NewQuickList() *QuickList {
    return &QuickList{
        head:   nil,
        tail:   nil,
        length: 0,
        count:  0,
    }
}

// 创建压缩列表
func NewZipList() *ZipList {
    return &ZipList{
        data:   make([]byte, 0),
        length: 0,
        tail:   0,
    }
}

2. 压缩列表操作

// quicklist/ziplist.go
package quicklist

// 压缩列表插入
func (zl *ZipList) Insert(index int, value []byte) error {
    if index < 0 || index > zl.length {
        return fmt.Errorf("index out of range")
    }
    
    // 简化的插入实现
    if index == zl.length {
        zl.data = append(zl.data, value...)
        zl.length++
        return nil
    }
    
    // 在中间插入
    newData := make([]byte, 0, len(zl.data)+len(value))
    newData = append(newData, zl.data[:index]...)
    newData = append(newData, value...)
    newData = append(newData, zl.data[index:]...)
    
    zl.data = newData
    zl.length++
    return nil
}

// 压缩列表删除
func (zl *ZipList) Delete(index int) error {
    if index < 0 || index >= zl.length {
        return fmt.Errorf("index out of range")
    }
    
    // 简化的删除实现
    if index == zl.length-1 {
        zl.data = zl.data[:len(zl.data)-1]
        zl.length--
        return nil
    }
    
    // 在中间删除
    newData := make([]byte, 0, len(zl.data)-1)
    newData = append(newData, zl.data[:index]...)
    newData = append(newData, zl.data[index+1:]...)
    
    zl.data = newData
    zl.length--
    return nil
}

// 压缩列表获取
func (zl *ZipList) Get(index int) ([]byte, error) {
    if index < 0 || index >= zl.length {
        return nil, fmt.Errorf("index out of range")
    }
    
    // 简化的获取实现
    return zl.data[index:index+1], nil
}

// 压缩列表长度
func (zl *ZipList) Length() int {
    return zl.length
}

3. QuickList 操作

// quicklist/operations.go
package quicklist

// 在头部插入
func (ql *QuickList) PushFront(value []byte) {
    ql.mu.Lock()
    defer ql.mu.Unlock()
    
    if ql.head == nil {
        // 创建第一个节点
        node := &QuickListNode{
            zl:   NewZipList(),
            size: 0,
        }
        ql.head = node
        ql.tail = node
    }
    
    // 在头部节点的压缩列表中插入
    if ql.head.zl.Length() < 8 { // 假设最大长度为 8
        ql.head.zl.Insert(0, value)
        ql.head.size++
    } else {
        // 创建新节点
        newNode := &QuickListNode{
            next: ql.head,
            zl:   NewZipList(),
            size: 0,
        }
        ql.head.prev = newNode
        ql.head = newNode
        ql.head.zl.Insert(0, value)
        ql.head.size++
    }
    
    ql.count++
}

// 在尾部插入
func (ql *QuickList) PushBack(value []byte) {
    ql.mu.Lock()
    defer ql.mu.Unlock()
    
    if ql.tail == nil {
        // 创建第一个节点
        node := &QuickListNode{
            zl:   NewZipList(),
            size: 0,
        }
        ql.head = node
        ql.tail = node
    }
    
    // 在尾部节点的压缩列表中插入
    if ql.tail.zl.Length() < 8 { // 假设最大长度为 8
        ql.tail.zl.Insert(ql.tail.zl.Length(), value)
        ql.tail.size++
    } else {
        // 创建新节点
        newNode := &QuickListNode{
            prev: ql.tail,
            zl:   NewZipList(),
            size: 0,
        }
        ql.tail.next = newNode
        ql.tail = newNode
        ql.tail.zl.Insert(0, value)
        ql.tail.size++
    }
    
    ql.count++
}

// 从头部弹出
func (ql *QuickList) PopFront() ([]byte, error) {
    ql.mu.Lock()
    defer ql.mu.Unlock()
    
    if ql.head == nil {
        return nil, fmt.Errorf("list is empty")
    }
    
    // 从头部节点的压缩列表中弹出
    value, err := ql.head.zl.Get(0)
    if err != nil {
        return nil, err
    }
    
    ql.head.zl.Delete(0)
    ql.head.size--
    ql.count--
    
    // 如果头部节点为空,删除它
    if ql.head.zl.Length() == 0 {
        if ql.head == ql.tail {
            ql.head = nil
            ql.tail = nil
        } else {
            ql.head = ql.head.next
            ql.head.prev = nil
        }
    }
    
    return value, nil
}

// 从尾部弹出
func (ql *QuickList) PopBack() ([]byte, error) {
    ql.mu.Lock()
    defer ql.mu.Unlock()
    
    if ql.tail == nil {
        return nil, fmt.Errorf("list is empty")
    }
    
    // 从尾部节点的压缩列表中弹出
    value, err := ql.tail.zl.Get(ql.tail.zl.Length() - 1)
    if err != nil {
        return nil, err
    }
    
    ql.tail.zl.Delete(ql.tail.zl.Length() - 1)
    ql.tail.size--
    ql.count--
    
    // 如果尾部节点为空,删除它
    if ql.tail.zl.Length() == 0 {
        if ql.head == ql.tail {
            ql.head = nil
            ql.tail = nil
        } else {
            ql.tail = ql.tail.prev
            ql.tail.next = nil
        }
    }
    
    return value, nil
}

// 获取长度
func (ql *QuickList) Length() int {
    ql.mu.RLock()
    defer ql.mu.RUnlock()
    return ql.count
}

// 检查是否为空
func (ql *QuickList) IsEmpty() bool {
    ql.mu.RLock()
    defer ql.mu.RUnlock()
    return ql.count == 0
}

测试验证

1. 双向链表测试

// list/doubly_linked_list_test.go
package list

import (
    "testing"
)

func TestDoublyLinkedList(t *testing.T) {
    dll := NewDoublyLinkedList()
    
    // 测试插入
    dll.PushFront(1)
    dll.PushBack(2)
    dll.Insert(1, 3)
    
    if dll.Length() != 3 {
        t.Errorf("Expected length 3, got %d", dll.Length())
    }
    
    // 测试获取
    val, err := dll.Get(0)
    if err != nil || val != 1 {
        t.Errorf("Expected 1, got %v", val)
    }
    
    val, err = dll.Get(1)
    if err != nil || val != 3 {
        t.Errorf("Expected 3, got %v", val)
    }
    
    val, err = dll.Get(2)
    if err != nil || val != 2 {
        t.Errorf("Expected 2, got %v", val)
    }
    
    // 测试删除
    val, err = dll.PopFront()
    if err != nil || val != 1 {
        t.Errorf("Expected 1, got %v", val)
    }
    
    val, err = dll.PopBack()
    if err != nil || val != 2 {
        t.Errorf("Expected 2, got %v", val)
    }
    
    if dll.Length() != 1 {
        t.Errorf("Expected length 1, got %d", dll.Length())
    }
}

func TestDoublyLinkedListConcurrent(t *testing.T) {
    dll := NewDoublyLinkedList()
    
    // 并发测试
    done := make(chan bool)
    
    // 写入协程
    go func() {
        for i := 0; i < 1000; i++ {
            dll.PushBack(i)
        }
        done <- true
    }()
    
    // 读取协程
    go func() {
        for i := 0; i < 1000; i++ {
            dll.Get(i % dll.Length())
        }
        done <- true
    }()
    
    // 等待完成
    <-done
    <-done
    
    if dll.Length() != 1000 {
        t.Errorf("Expected length 1000, got %d", dll.Length())
    }
}

2. 跳跃表测试

// skiplist/skiplist_test.go
package skiplist

import (
    "testing"
)

func TestSkipList(t *testing.T) {
    sl := NewSkipList(16)
    
    // 测试插入
    sl.Insert("key1", "value1")
    sl.Insert("key2", "value2")
    sl.Insert("key3", "value3")
    
    if sl.Length() != 3 {
        t.Errorf("Expected length 3, got %d", sl.Length())
    }
    
    // 测试查找
    val, exists := sl.Search("key1")
    if !exists || val != "value1" {
        t.Errorf("Expected 'value1', got %v", val)
    }
    
    val, exists = sl.Search("key2")
    if !exists || val != "value2" {
        t.Errorf("Expected 'value2', got %v", val)
    }
    
    // 测试删除
    if !sl.Delete("key1") {
        t.Error("Failed to delete key1")
    }
    
    _, exists = sl.Search("key1")
    if exists {
        t.Error("Key1 should not exist after deletion")
    }
    
    if sl.Length() != 2 {
        t.Errorf("Expected length 2, got %d", sl.Length())
    }
}

func TestSkipListRange(t *testing.T) {
    sl := NewSkipList(16)
    
    // 插入测试数据
    for i := 0; i < 100; i++ {
        key := fmt.Sprintf("key%d", i)
        value := fmt.Sprintf("value%d", i)
        sl.Insert(key, value)
    }
    
    // 测试范围查询
    result := sl.SearchRange("key10", "key20")
    if len(result) != 11 {
        t.Errorf("Expected 11 results, got %d", len(result))
    }
    
    // 测试排名
    rank := sl.GetRank("key50")
    if rank != 50 {
        t.Errorf("Expected rank 50, got %d", rank)
    }
    
    // 测试根据排名获取
    val, exists := sl.GetByRank(25)
    if !exists || val != "value25" {
        t.Errorf("Expected 'value25', got %v", val)
    }
}

3. 性能基准测试

// list/benchmark_test.go
package list

import (
    "testing"
)

func BenchmarkDoublyLinkedListPushBack(b *testing.B) {
    dll := NewDoublyLinkedList()
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        dll.PushBack(i)
    }
}

func BenchmarkDoublyLinkedListPushFront(b *testing.B) {
    dll := NewDoublyLinkedList()
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        dll.PushFront(i)
    }
}

func BenchmarkDoublyLinkedListGet(b *testing.B) {
    dll := NewDoublyLinkedList()
    
    // 预填充数据
    for i := 0; i < 1000; i++ {
        dll.PushBack(i)
    }
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        dll.Get(i % 1000)
    }
}

func BenchmarkGoSliceAppend(b *testing.B) {
    var slice []int
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        slice = append(slice, i)
    }
}

func BenchmarkGoSlicePrepend(b *testing.B) {
    var slice []int
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        slice = append([]int{i}, slice...)
    }
}

性能对比分析

1. 操作复杂度对比

操作双向链表跳跃表平衡树说明
查找O(n)O(log n)O(log n)跳跃表概率性
插入O(1)O(log n)O(log n)链表在已知位置
删除O(1)O(log n)O(log n)链表在已知位置
范围查询O(n)O(log n + k)O(log n + k)k 为结果数量

2. 内存使用对比

特性双向链表跳跃表平衡树说明
内存开销低中等中等跳跃表需要额外指针
内存局部性差好好跳跃表节点连续
缓存友好性差好好跳跃表访问模式更好

3. 性能测试结果

// 基准测试结果示例
func BenchmarkComparison(b *testing.B) {
    // 双向链表性能
    b.Run("DoublyLinkedList", func(b *testing.B) {
        dll := NewDoublyLinkedList()
        for i := 0; i < b.N; i++ {
            dll.PushBack(i)
        }
    })
    
    // 跳跃表性能
    b.Run("SkipList", func(b *testing.B) {
        sl := NewSkipList(16)
        for i := 0; i < b.N; i++ {
            sl.Insert(i, i)
        }
    })
    
    // Go 切片性能
    b.Run("GoSlice", func(b *testing.B) {
        var slice []int
        for i := 0; i < b.N; i++ {
            slice = append(slice, i)
        }
    })
}

面试要点

1. 跳跃表的优势

答案要点:

  • 简单实现:比平衡树更容易实现
  • 并发友好:支持无锁并发操作
  • 范围查询:高效支持范围查询
  • 内存效率:比平衡树使用更少内存

2. 跳跃表的层数选择

答案要点:

  • 概率性:每层有 50% 概率
  • 期望层数:log₂(n) 层
  • 最大层数:通常限制在 16-32 层
  • 性能平衡:层数过多浪费内存,过少影响性能

3. QuickList 的设计思想

答案要点:

  • 空间效率:压缩列表减少内存使用
  • 访问效率:双向链表支持快速插入删除
  • 平衡点:在内存使用和性能之间平衡
  • 分段存储:避免大块内存分配

4. 链表 vs 数组的选择

答案要点:

  • 插入删除:链表 O(1),数组 O(n)
  • 随机访问:链表 O(n),数组 O(1)
  • 内存使用:链表有指针开销,数组连续存储
  • 缓存友好性:数组更好,链表较差

总结

通过本章学习,我们深入理解了:

  1. 双向链表的实现和优化技巧
  2. 跳跃表的原理和概率分析
  3. 完整的跳表算法实现
  4. QuickList 的设计思想和实现
  5. 与平衡树的性能对比分析

列表和跳表为 Redis 提供了高效的有序数据结构支持。在下一章中,我们将学习有序集合实现,了解 Redis 如何结合跳表和字典实现 ZSet。

Prev
哈希表与字典实现
Next
有序集合实现