欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据结构之-跳跃表(skip list, scala版)

程序员文章站 2024-01-09 20:29:16
...

概述    

SkipList 是由William Pugh发明的一种数据结构,它的作用类似平衡二叉树,对查找,删除,插入操作的时间复杂度为O(logN),是一种十分高效的查找结构。SkipList使用随机化的平衡方案取代了平衡二叉树的严格的平衡方案,因此它也是一种随机化的数据结构。SkipList基于并联的链表,是对有序的链表附加上随机个数的前进的链接,使得在查找过程中可以快速地跳过部分链表而得名。
数据结构之-跳跃表(skip list, scala版)
            
    
    博客分类: 算法 数据结构skipList跳表跳跃表scala
     如上图所示,a为普通的排好序的LinkList,在a中查找一个元素,最坏情况下,我们需要对比所有的节点,如果修改成如b那样,间隔的list中的元素加上指向前面第二个的元素指针,则查找一个元素最多需要【n/2】+ 1次对比,同理对应c来说,则需要【n/4】 + 1次,如果对任意第2^i个节点拥有i个指针来指向前面的i个节点,那么其查找效率就会降到logN,但是这种数据结构虽然可以很快的进行查找,但是对于插入和删除操作确实不切实际的。一个拥有k个向前指针的节点称为k层节点,像之前描述的结构,节点的层次分布模式为:%50为1层,25%为2层,12.5%为三层,以此类推。如果按一定比例来随机分配节点的层次的话(如图中的e),节点的第i个向前指针只需指向第i层的下一个节点。当插入一个节点时,随机的选择它的层次,并且不再需要改变。虽然有时候某些层次的安排会带来低效的执行效率,但是因为是随机化的,所以这种情况是很罕见的。

初始化

SkipList的所有层级的子list都终结于NIL(不带任何合法值的元素),刚创建的SkipList的层级为1,只有一个头结点,并且只包含一个指向NIL的向前结点。

随机化层次选择

设拥有第i个向前指针的节点,同时拥有第i+1个向前指针分布比例为p,若有一半的节点有第i个向前指针的节点,同时拥有第i+1个向前指针,则p等于1/2.则随机化的层次选择过程如下:

randomLevel()
lvl := 1
-- random() that returns a random value in [0...1)
while random() < p and lvl < MaxLevel do
lvl := lvl + 1
return lvl

 这里有个MaxLevel,它的值为 MaxLevel =L(N)= log(1/p)N (p=1/2)=log(2).N,它表示跳跃表最大允许的层次。

效率分析

设C(K)为查找第k个节点需要消耗的时间,则:

C(0) = 0
C(k) = (1–p) (在同一层查找) + p (向下一层查找)

 

化简得

C(k) = (1–p) (1 + C(k)) + p (1 + C(k–1))
C(k) = 1/p + C(k–1)
C(k) = k/p

 因为k《=MaxLevel=L(n)/p + 1/(1–p),为O(logN)

 

查找过程

Search(list, searchKey)
      x := list.eader
      -- loop invariant: x.key < searchKey
      for i := list.level downto 1 do
          while x.forward[i].key < searchKey do
                x := x.forward[i]
      -- x.key < searchKey <= x.forward[1].key
      x := x.forward[1]
      if x.key = searchKey then return x.value
      else return failure

 

模拟查找过程:


数据结构之-跳跃表(skip list, scala版)
            
    
    博客分类: 算法 数据结构skipList跳表跳跃表scala
 

查找6的过程如下:

 

  • 首先从最高层开始,发现6在 header跟6节点之间
  • 然后继续降到第三层
  • 还是发现6在 header跟6节点之间,降到第二层
  • 第一层时,发现6在节点3和6直接,此时x指向3这个节点
  • 3的下一个节点是6,刚好找到

 

插入过程

Insert(list, searchKey, newValue)
    local update[1..MaxLevel]
    x := list.header
    for i := list.level downto 1 do
         while x.forward[i].key < searchKey do
              x := x.forward[i]
         -- x.key < searchKey £ x.forward[i].key
         update[i] := x
    x := x.forward[1]
   if x.key = searchKey then x.value := newValue
   else
        lvl := randomLevel()
        if lvl > list.level then
        for i := list.level + 1 to lvl do
             update[i] := list.header
             list.level := lvl
        x := makeNode(lvl, searchKey, value)
        for i := 1 to level do
              x.forward[i] := update[i].forward[i]
              update[i].forward[i] := x

 删除过程

 

Delete(list, searchKey)
     local update[1..MaxLevel]
     x := list.header
     for i := list.level downto 1 do
          while x.forward[i].key < searchKey do
                  x := x.forward[i]
          update[i] := x
     x := x.forward[1]
     if x.key = searchKey then
          for i := 1 to list.level do
               if update[i].forward[i] != x then break
               update[i].forward[i] := x.forward[i]
          free(x)
          while list.level > 1 and
                 list.header.forward[list.level] = NIL do
                 list.level := list.level – 1
 

 

 SCALA实现

package chiyx.algo.datastruct

/**
 * Created with IntelliJ IDEA.
 * scala版本的跳跃表的实现
 * @author qianshang@taobao.com
 * @since 下午11:00 13-9-2
 *
 */
class SkipList[T <% Ordered[T]] {

  /**
   * 随机化的概率,每层节点拥有上一层指针的概率
   */
  private val P = 0.5

  /**
   * 最高层级为8,则 N的合适范围在 2^^8
   */
  private val MaxLevel = 8

  private val header: SkipNode[T] = new SkipNode[T](MaxLevel)

  /**
   * 当前的最大层级编号,从0开始编号
   */
  private var level = 0

  /**
   * 随机产生插入节点的层高
   * @return
   */
  def randomLevel = {
    val lvl = (Math.log(1.0 - Math.random()) / Math.log(1 - P)).toInt
    Math.min(lvl, MaxLevel)
  }

  /**
   * 检查是否包含元素
   * @param o
   * @return
   */
  def contains(o: T) = {
    var x = header
    for (i <- level.to(0, -1)) {
      while (x.forward(i) != null && x.forward(i).value < o) {
        x = x.forward(i)
      }
    }
    x = x.forward(0)
    x != null && x.value.equals(o)
  }

  /**
   * 插入元素
   * @param o
   */
  def insert(o: T) {
    var x = header
    val update = new Array[SkipNode[T]](MaxLevel + 1)
    for (i <- level.to(0, -1)) {
      while (x.forward(i) != null && x.forward(i).value < o) {
        x = x.forward(i)
      }
      update(i) = x
    }
    x = x.forward(0)

    /**
     * 如果不存在,则创建节点
     */
    if (x == null || x.value != o) {
      val  lvl = randomLevel
      if (lvl > level) {
        for (i <- level to lvl) {
          update(i) = header
        }
        level = lvl
      }
      x = new SkipNode[T](o, lvl)
      for (i <- 0 to lvl) {
        x.forward(i) = update(i).forward(i)
        update(i).forward(i) = x
      }
    }

  }

  /**
   * 删除操作
   * @param o
   */
  def delete(o: T) {
    var x = header
    val update = new Array[SkipNode[T]](MaxLevel + 1)
    for (i <- level.to(0, -1)) {
      while (x.forward(i) != null && x.forward(i).value < o) {
        x = x.forward(i)
      }
      update(i) = x
    }
    x = x.forward(0)
    //元素存在的情况下才需要删除
    if (x != null && x.value == o) {
      for (i <- 0 to level) {
        if (update(i).forward(i) == x) {
          update(i).forward(i) = x.forward(i)
        }
      }
      while (level > 0 && header.forward(level) == null) {
        level = level - 1
      }
    }
  }
}


/**
 * 跳跃表中的节点
 * @tparam T
 */
private class SkipNode[T](val level: Int) {

  var value: T = _

  /**
   * 指向多个层级的下个节点的指针数组
   */
  val forward: Array[SkipNode[T]] = new Array[SkipNode[T]](level + 1)

  def this(ve: T, level: Int) = {
    this(level)
    value = ve
  }
}

object SkipListApp {
  def main(args: Array[String]) {
    val sList = new SkipList[Int]
    sList insert 5
    sList insert 4
    sList insert 6
    sList insert 9
    println( sList contains 6)
    sList delete 6
    println( sList contains 6)
  }
}

 

 

  • 数据结构之-跳跃表(skip list, scala版)
            
    
    博客分类: 算法 数据结构skipList跳表跳跃表scala
  • 大小: 109 KB
  • 数据结构之-跳跃表(skip list, scala版)
            
    
    博客分类: 算法 数据结构skipList跳表跳跃表scala
  • 大小: 17.6 KB