| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
jope3014
9年前发布

skiplist(跳表)算法实现

跳表是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的。

下面来研究一下跳表的核心思想:

先从链表开始,如果是一个简单的链表,那么我们知道在链表中查找一个元素I的话,需要将整个链表遍历一次。

 

 如果是说链表是排序的,并且节点中还存储了指向前面第二个节点的指针的话,那么在查找一个节点时,仅仅需要遍历N/2个节点即可。

 

这基本上就是跳表的核心思想,其实也是一种通过“空间来换取时间”的一个算法,通过在每个节点中增加了向前的指针,从而提升查找的效率。

跳表的数据存储模型 

 我们定义:

如果一个基点存在k个向前的指针的话,那么陈该节点是k层的节点。

一个跳表的层MaxLevel义为跳表中所有节点中最大的层数。

下面给出一个完整的跳表的图示:

 

 那么我们该如何将该数据结构使用二进制存储呢?通过上面的跳表的很容易设计这样的数据结构:

定义每个节点类型:

//定义每个节点类型:  type nodeStructure struct {   key     int // key值   value   int // value值   forward []*nodeStructure  }

上面的每个结构体对应着图中的每个节点,如果一个节点是一层的节点的话(如7,12等节点),那么对应的forward将指向一个只含一个元素的数组,以此类推。

 定义跳表数据类型:

// 定义跳表数据类型  type listStructure struct {   level  int            /* Maximum level of the list (1 more than the number of levels in the list) */   header *nodeStructure /* pointer to header */  }

跳表数据类型中包含了维护跳表的必要信息,level表明跳表的层数,header如下所示:

 

初始化的过程很简单,仅仅是生成下图中红线区域内的部分,也就是跳表的基础结构:

//跳表初始化  func newList() *listStructure {   var l *listStructure   var i int   // 申请list类型大小的内存   l = &listStructure{}   // 设置跳表的层level,初始的层为0层(数组从0开始)   l.level = 0     // 生成header部分   l.header = newNodeOfLevel(MaxNumberOfLevels)   // 将header的forward数组清空   for i = 0; i < MaxNumberOfLevels; i++ {    l.header.forward[i] = nil   }   return l  }

插入操作

由于跳表数据结构整体上是有序的,所以在插入时,需要首先查找到合适的位置,然后就是修改指针(和链表中操作类似),然后更新跳表的level变量。

 

func insert(l *listStructure, key int, value int) bool {   var k int   // 使用了update数组   var update [MaxNumberOfLevels]*nodeStructure   var p, q *nodeStructure   p = l.header   k = l.level   fmt.Printf("list level: %v\n", k)     for ; k >= 0; k-- {    // 查找插入位置    q = p.forward[k]    for q != nil && q.key < key {     p = q     q = p.forward[k]    }      // 设置update数组    update[k] = p     } // 对于每一层进行遍历 一直到最低层     // 这里已经查找到了合适的位置,并且update数组已经   // 填充好了元素 貌似不插入重复元素   if q != nil && q.key == key {    q.value = value    return false   }     // 随机生成一个层数   k = randomLevel()   fmt.Printf("random Level: %v\n", k)     if k > l.level {    // 如果新生成的层数比跳表的层数大的话    // 增加整个跳表的层数    l.level++    k = l.level    // 在update数组中将新添加的层指向l->header    update[k] = l.header   }     // 生成层数个节点数目   q = newNodeOfLevel(k + 1)   q.key = key   q.value = value     // 每层插入节点   for ; k >= 0; k-- {    p = update[k]    q.forward[k] = p.forward[k]    p.forward[k] = q   }     // 如果程序运行到这里,程序已经插入了该节点   return true  }

删除某个节点

和插入是相同的,首先查找需要删除的节点,如果找到了该节点的话,那么只需要更新指针域,如果跳表的level需要更新的话,进行更新。

 

func delete(l *listStructure, key int) bool {   var k, m int   // 生成一个辅助数组update   var update [MaxNumberOfLevels]*nodeStructure   var p, q *nodeStructure   p = l.header   k = l.level   m = l.level     //指向该节点对应层的前驱节点 一直到最低层   for ; k >= 0; k-- {      q = p.forward[k]    for q != nil && q.key < key {     p = q     q = p.forward[k]    }    update[k] = p     }     // 如果找到了该节点,才进行删除的动作   if q != nil && q.key == key {    // 指针运算    for k = 0; k <= m && update[k].forward[k] == q; k++ {     // 这里可能修改l.header.forward数组的值的     p = update[k]     p.forward[k] = q.forward[k]    }      // 如果删除的是最大层的节点,那么需要重新维护跳表的    // 层数level    for l.header.forward[m] == nil && m > 0 {     m--    }      l.level = m    return true     } else {    return false     }  }

skiplist完整代码

package main    import (   "fmt"   "math/rand"   "time"  )    //定义每个节点类型:  type nodeStructure struct {   key     int // key值   value   int // value值   forward []*nodeStructure  }    // 定义跳表数据类型  type listStructure struct {   level  int            /* Maximum level of the list (1 more than the number of levels in the list) */   header *nodeStructure /* pointer to header */  }    const (   MaxNumberOfLevels = 11   MaxLevel          = 10  )    // newNodeOfLevel生成一个nodeStructure结构体,同时生成l个*nodeStructure数组指针  //#define newNodeOfLevel(l) (*nodeStructure)malloc(sizeof(struct nodeStructure)+(l)*sizeof(nodeStructure *))    func newNodeOfLevel(level int) *nodeStructure {   nodearr := make([]*nodeStructure, level) //new([level]*node)   return &nodeStructure{forward: nodearr}  }    //跳表初始化  func newList() *listStructure {   var l *listStructure   var i int   // 申请list类型大小的内存   l = &listStructure{}   // 设置跳表的层level,初始的层为0层(数组从0开始)   l.level = 0     // 生成header部分   l.header = newNodeOfLevel(MaxNumberOfLevels)   // 将header的forward数组清空   for i = 0; i < MaxNumberOfLevels; i++ {    l.header.forward[i] = nil   }   return l  }    func randomLevel() int {   r := rand.New(rand.NewSource(time.Now().UnixNano()))   return r.Intn(MaxLevel)  }    func insert(l *listStructure, key int, value int) bool {   var k int   // 使用了update数组   var update [MaxNumberOfLevels]*nodeStructure   var p, q *nodeStructure   p = l.header   k = l.level     for ; k >= 0; k-- {    // 查找插入位置    q = p.forward[k]    for q != nil && q.key < key {     p = q     q = p.forward[k]    }      // 设置update数组    update[k] = p     } // 对于每一层进行遍历 一直到最低层     // 这里已经查找到了合适的位置,并且update数组已经   // 填充好了元素 貌似不插入重复元素   if q != nil && q.key == key {    q.value = value    return false   }     // 随机生成一个层数   k = randomLevel()     if k > l.level {    // 如果新生成的层数比跳表的层数大的话    // 增加整个跳表的层数    l.level++    k = l.level    // 在update数组中将新添加的层指向l->header    update[k] = l.header   }     // 生成层数个节点数目   q = newNodeOfLevel(k + 1)   q.key = key   q.value = value     // 每层插入节点   for ; k >= 0; k-- {    p = update[k]    q.forward[k] = p.forward[k]    p.forward[k] = q   }     // 如果程序运行到这里,程序已经插入了该节点   return true  }    func delete(l *listStructure, key int) bool {   var k, m int   // 生成一个辅助数组update   var update [MaxNumberOfLevels]*nodeStructure   var p, q *nodeStructure   p = l.header   k = l.level   m = l.level     //指向该节点对应层的前驱节点 一直到最低层   for ; k >= 0; k-- {      q = p.forward[k]    for q != nil && q.key < key {     p = q     q = p.forward[k]    }    update[k] = p     }     // 如果找到了该节点,才进行删除的动作   if q != nil && q.key == key {    // 指针运算    for k = 0; k <= m && update[k].forward[k] == q; k++ {     // 这里可能修改l.header.forward数组的值的     p = update[k]     p.forward[k] = q.forward[k]    }      // 如果删除的是最大层的节点,那么需要重新维护跳表的    // 层数level    for l.header.forward[m] == nil && m > 0 {     m--    }      l.level = m    return true     } else {    return false     }  }    func search(l *listStructure, key int) int {   var k int     var p, q *nodeStructure   p = l.header   k = l.level     //指向该节点对应层的前驱节点 一直到最低层   for ; k >= 0; k-- {      q = p.forward[k]    for q != nil && q.key < key {     q = q.forward[k]    }      if q != nil && q.key == key {     return q.value    }   }     if q != nil && q.key == key {    return q.value   } else {    return -1   }  }    func main() {   l := newList()     insert(l, 3, 30)   insert(l, 6, 60)   insert(l, 7, 70)   insert(l, 9, 90)     delete(l, 9)     insert(l, 12, 120)   insert(l, 17, 170)   insert(l, 19, 190)     fmt.Printf("skiplist:%v\n", search(l, 12))   fmt.Printf("skiplist:%v\n", search(l, 9))  }

程序输出结果:

skiplist:120  skiplist:-1