go实现一个跳表

243 阅读3分钟

跳表的定义

增加了向前指针的链表叫作跳表。跳表全称叫做跳跃表,简称跳表。 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。 跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。

image.png

coding

import (
   "math/bits"
   "math/rand"
)

const (
   maxLevel = 16
)

// Element is a key-score pair
type Element struct {
   Member string
   Score  float64
}

// Level aspect of a node
type Level struct {
   forward *node // forward node has greater score
   span    int64
}

type node struct {
   Element
   backward *node
   level    []*Level // level[0] is base level
}

type skiplist struct {
   header *node
   tail   *node
   length int64
   level  int16
}

func makeNode(level int16, score float64, member string) *node {
   n := &node{
      Element: Element{
         Score:  score,
         Member: member,
      },
      level: make([]*Level, level),
   }
   for i := range n.level {
      n.level[i] = new(Level)
   }
   return n
}

func makeSkiplist() *skiplist {
   return &skiplist{
      level:  1,
      header: makeNode(maxLevel, 0, ""),
   }
}

func randomLevel() int16 {
   total := uint64(1)<<uint64(maxLevel) - 1
   k := rand.Uint64() % total
   return maxLevel - int16(bits.Len64(k+1)) + 1
}

func (skiplist *skiplist) insert(member string, score float64) *node {
   update := make([]*node, maxLevel) // link new node with node in `update`
   rank := make([]int64, maxLevel)
   // find position to insert
   node := skiplist.header
   for i := skiplist.level - 1; i >= 0; i-- {
      if i == skiplist.level-1 {
         rank[i] = 0
      } else {
         rank[i] = rank[i+1] // store rank that is crossed to reach the insert position
      }
      if node.level[i] != nil {
         // traverse the skip list
         for node.level[i].forward != nil &&
            (node.level[i].forward.Score < score ||
               (node.level[i].forward.Score == score && node.level[i].forward.Member < member)) { // same score, different key
            rank[i] += node.level[i].span
            node = node.level[i].forward
         }
      }
      update[i] = node
   }

   level := randomLevel()
   // extend skiplist level
   if level > skiplist.level {
      for i := skiplist.level; i < level; i++ {
         rank[i] = 0
         update[i] = skiplist.header
         update[i].level[i].span = skiplist.length
      }
      skiplist.level = level
   }

   // make node and link into skiplist
   node = makeNode(level, score, member)
   for i := int16(0); i < level; i++ {
      node.level[i].forward = update[i].level[i].forward
      update[i].level[i].forward = node

      // update span covered by update[i] as node is inserted here
      node.level[i].span = update[i].level[i].span - (rank[0] - rank[i])
      update[i].level[i].span = (rank[0] - rank[i]) + 1
   }

   // increment span for untouched levels
   for i := level; i < skiplist.level; i++ {
      update[i].level[i].span++
   }

   // set backward node
   if update[0] == skiplist.header {
      node.backward = nil
   } else {
      node.backward = update[0]
   }
   if node.level[0].forward != nil {
      node.level[0].forward.backward = node
   } else {
      skiplist.tail = node
   }
   skiplist.length++
   return node
}

/*
 * param node: node to delete
 * param update: backward node (of target)
 */
func (skiplist *skiplist) removeNode(node *node, update []*node) {
   for i := int16(0); i < skiplist.level; i++ {
      if update[i].level[i].forward == node {
         update[i].level[i].span += node.level[i].span - 1
         update[i].level[i].forward = node.level[i].forward
      } else {
         update[i].level[i].span--
      }
   }
   if node.level[0].forward != nil {
      node.level[0].forward.backward = node.backward
   } else {
      skiplist.tail = node.backward
   }
   for skiplist.level > 1 && skiplist.header.level[skiplist.level-1].forward == nil {
      skiplist.level--
   }
   skiplist.length--
}

/*
 * return: has found and removed node
 */
func (skiplist *skiplist) remove(member string, score float64) bool {
   /*
    * find backward node (of target) or last node of each level
    * their forward need to be updated
    */
   update := make([]*node, maxLevel)
   node := skiplist.header
   for i := skiplist.level - 1; i >= 0; i-- {
      for node.level[i].forward != nil &&
         (node.level[i].forward.Score < score ||
            (node.level[i].forward.Score == score &&
               node.level[i].forward.Member < member)) {
         node = node.level[i].forward
      }
      update[i] = node
   }
   node = node.level[0].forward
   if node != nil && score == node.Score && node.Member == member {
      skiplist.removeNode(node, update)
      // free x
      return true
   }
   return false
}

/*
 * return: 1 based rank, 0 means member not found
 */
func (skiplist *skiplist) getRank(member string, score float64) int64 {
   var rank int64 = 0
   x := skiplist.header
   for i := skiplist.level - 1; i >= 0; i-- {
      for x.level[i].forward != nil &&
         (x.level[i].forward.Score < score ||
            (x.level[i].forward.Score == score &&
               x.level[i].forward.Member <= member)) {
         rank += x.level[i].span
         x = x.level[i].forward
      }

      /* x might be equal to zsl->header, so test if obj is non-NULL */
      if x.Member == member {
         return rank
      }
   }
   return 0
}

/*
 * 1-based rank
 */
func (skiplist *skiplist) getByRank(rank int64) *node {
   var i int64 = 0
   n := skiplist.header
   // scan from top level
   for level := skiplist.level - 1; level >= 0; level-- {
      for n.level[level].forward != nil && (i+n.level[level].span) <= rank {
         i += n.level[level].span
         n = n.level[level].forward
      }
      if i == rank {
         return n
      }
   }
   return nil
}

func (skiplist *skiplist) hasInRange(min *ScoreBorder, max *ScoreBorder) bool {
   // min & max = empty
   if min.Value > max.Value || (min.Value == max.Value && (min.Exclude || max.Exclude)) {
      return false
   }
   // min > tail
   n := skiplist.tail
   if n == nil || !min.less(n.Score) {
      return false
   }
   // max < head
   n = skiplist.header.level[0].forward
   if n == nil || !max.greater(n.Score) {
      return false
   }
   return true
}

func (skiplist *skiplist) getFirstInScoreRange(min *ScoreBorder, max *ScoreBorder) *node {
   if !skiplist.hasInRange(min, max) {
      return nil
   }
   n := skiplist.header
   // scan from top level
   for level := skiplist.level - 1; level >= 0; level-- {
      // if forward is not in range than move forward
      for n.level[level].forward != nil && !min.less(n.level[level].forward.Score) {
         n = n.level[level].forward
      }
   }
   /* This is an inner range, so the next node cannot be NULL. */
   n = n.level[0].forward
   if !max.greater(n.Score) {
      return nil
   }
   return n
}

func (skiplist *skiplist) getLastInScoreRange(min *ScoreBorder, max *ScoreBorder) *node {
   if !skiplist.hasInRange(min, max) {
      return nil
   }
   n := skiplist.header
   // scan from top level
   for level := skiplist.level - 1; level >= 0; level-- {
      for n.level[level].forward != nil && max.greater(n.level[level].forward.Score) {
         n = n.level[level].forward
      }
   }
   if !min.less(n.Score) {
      return nil
   }
   return n
}

/*
 * return removed elements
 */
func (skiplist *skiplist) RemoveRangeByScore(min *ScoreBorder, max *ScoreBorder, limit int) (removed []*Element) {
   update := make([]*node, maxLevel)
   removed = make([]*Element, 0)
   // find backward nodes (of target range) or last node of each level
   node := skiplist.header
   for i := skiplist.level - 1; i >= 0; i-- {
      for node.level[i].forward != nil {
         if min.less(node.level[i].forward.Score) { // already in range
            break
         }
         node = node.level[i].forward
      }
      update[i] = node
   }

   // node is the first one within range
   node = node.level[0].forward

   // remove nodes in range
   for node != nil {
      if !max.greater(node.Score) { // already out of range
         break
      }
      next := node.level[0].forward
      removedElement := node.Element
      removed = append(removed, &removedElement)
      skiplist.removeNode(node, update)
      if limit > 0 && len(removed) == limit {
         break
      }
      node = next
   }
   return removed
}

// 1-based rank, including start, exclude stop
func (skiplist *skiplist) RemoveRangeByRank(start int64, stop int64) (removed []*Element) {
   var i int64 = 0 // rank of iterator
   update := make([]*node, maxLevel)
   removed = make([]*Element, 0)

   // scan from top level
   node := skiplist.header
   for level := skiplist.level - 1; level >= 0; level-- {
      for node.level[level].forward != nil && (i+node.level[level].span) < start {
         i += node.level[level].span
         node = node.level[level].forward
      }
      update[level] = node
   }

   i++
   node = node.level[0].forward // first node in range

   // remove nodes in range
   for node != nil && i < stop {
      next := node.level[0].forward
      removedElement := node.Element
      removed = append(removed, &removedElement)
      skiplist.removeNode(node, update)
      node = next
      i++
   }
   return removed
}

一些亮点

在randomLevel这个函数中total的值是16位1,对total取余后的取值是0到11111_11111_111110。对这个数值域加一后,在这个数值域中第一位1出现在最高位的概率是1/2,出现在第二位的概率是1/4。所以用第一位1出现的位置来决定层数即可保证不相等概率的选取层数