如何使用Go 实现 redis 跳表?

195 min read

实现 redis 跳表可以按照以下步骤:

  1. 定义数据结构 SkipList,包含节点修建的 Level 数组。
type SkipList struct {
    Header *SkipListNode
    Level  int
}

type SkipListNode struct {
    Key   int
    Value interface{}
    Level []*SkipListNode
}
  1. 初始化跳表,将头节点和 Level 数组初始化。Level 数组用于记录每个节点在哪些层有后继节点。
func NewSkipListWithLevel(level int) *SkipList {
    header := &SkipListNode{
        Key:   math.MinInt32,
        Value: nil,
        Level: make([]*SkipListNode, level),
    }
    return &SkipList{
        Header: header,
        Level:  level,
    }
}
  1. 插入节点,从最高层开始逐层寻找插入位置,将新节点插入其中。
func (list *SkipList) Insert(key int, value interface{}) {
    node := &SkipListNode{
        Key:   key,
        Value: value,
        Level: make([]*SkipListNode, list.randomLevel()),
    }

    // 找到每层需要插入的位置
    update := make([]*SkipListNode, list.Level)
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
        update[i] = x
    }

    // 插入节点到每层
    for i := 0; i < len(node.Level); i++ {
        node.Level[i] = update[i].Level[i]
        update[i].Level[i] = node
    }
}
  1. 删除节点,和插入节点类似,先找到每层需要删除的位置,然后逐层删除。
func (list *SkipList) Delete(key int) bool {
    // 找到每层需要删除的位置
    update := make([]*SkipListNode, list.Level)
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
        update[i] = x
    }

    // 删除节点
    if x.Level[0] != nil && x.Level[0].Key == key {
        for i := 0; i < list.Level; i++ {
            if update[i].Level[i] != nil && update[i].Level[i].Key == key {
                update[i].Level[i] = update[i].Level[i].Level[i]
            }
        }
        return true
    }
    return false
}
  1. 搜索节点,从最高层开始逐层查找。
func (list *SkipList) Search(key int) interface{} {
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
    }
    if x.Level[0] != nil && x.Level[0].Key == key {
        return x.Level[0].Value
    }
    return nil
}

完整实现代码如下:

package skiplist

import (
    "math"
    "math/rand"
)

type SkipList struct {
    Header *SkipListNode
    Level  int
}

type SkipListNode struct {
    Key   int
    Value interface{}
    Level []*SkipListNode
}

func NewSkipListWithLevel(level int) *SkipList {
    header := &SkipListNode{
        Key:   math.MinInt32,
        Value: nil,
        Level: make([]*SkipListNode, level),
    }
    return &SkipList{
        Header: header,
        Level:  level,
    }
}

func (list *SkipList) randomLevel() int {
    level := 1
    for rand.Float32() < 0.5 && level < list.Level {
        level++
    }
    return level
}

func (list *SkipList) Insert(key int, value interface{}) {
    node := &SkipListNode{
        Key:   key,
        Value: value,
        Level: make([]*SkipListNode, list.randomLevel()),
    }

    // 找到每层需要插入的位置
    update := make([]*SkipListNode, list.Level)
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
        update[i] = x
    }

    // 插入节点到每层
    for i := 0; i < len(node.Level); i++ {
        node.Level[i] = update[i].Level[i]
        update[i].Level[i] = node
    }
}

func (list *SkipList) Delete(key int) bool {
    // 找到每层需要删除的位置
    update := make([]*SkipListNode, list.Level)
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
        update[i] = x
    }

    // 删除节点
    if x.Level[0] != nil && x.Level[0].Key == key {
        for i := 0; i < list.Level; i++ {
            if update[i].Level[i] != nil && update[i].Level[i].Key == key {
                update[i].Level[i] = update[i].Level[i].Level[i]
            }
        }
        return true
    }
    return false
}

func (list *SkipList) Search(key int) interface{} {
    x := list.Header
    for i := list.Level - 1; i >= 0; i-- {
        for x.Level[i] != nil && x.Level[i].Key < key {
            x = x.Level[i]
        }
    }
    if x.Level[0] != nil && x.Level[0].Key == key {
        return x.Level[0].Value
    }
    return nil
}

使用跳表的示例:

package main

import (
    "fmt"

    "skiplist"
)

func main() {
    list := skiplist.NewSkipListWithLevel(4)
    list.Insert(1, "one")
    list.Insert(2, "two")
    list.Insert(3, "three")
    list.Insert(4, "four")
    list.Insert(5, "five")

    fmt.Println(list.Search(3)) // output: three
    fmt.Println(list.Search(6)) // output: nil

    list.Delete(3)
    fmt.Println(list.Search(3)) // output: nil
}