跳跃表实现与原理

来源:互联网 发布:淘宝打单插件 编辑:程序博客网 时间:2024/05/20 19:48
/** 
 *  跳表节点数据存储结构  */  class SkipNode<E extends Comparable<? super E>> {      public final E value; //节点存储的数据      public final SkipNode<E>[] forward; //节点的指针数组            /**      * 根据节点的层级构造一个节点      * @param level 节点层级      * @param value 节点存储值      */      @SuppressWarnings("unchecked")      public SkipNode(int level, E value) {          forward = new SkipNode[level + 1];//level层的元素后面带着level+1的指针数组          this.value = value;      }    }    public class SkipSet<E extends Comparable<? super E>> {            /**      * 概率因子,实验证明p=1/e比p=0.5要好,e是个神奇的数字!      */  //  public static final double P = 0.5;      public static final double P = 1/Math.E;      /**      *  最大层级      */      public static final int MAX_LEVEL = 6;            /**      * 开始节点,不存值,贯穿所有层      */      public final SkipNode<E> header = new SkipNode<E>(MAX_LEVEL, null);      /**      * 当前跳表的最高层级      */      public int level = 0;            /**      * 插入一个元素      * @param value 待插入值      */      @SuppressWarnings("unchecked")      public void insert(E value) {          SkipNode<E> x = header;          SkipNode<E>[] update = new SkipNode[MAX_LEVEL + 1];          //查找元素的位置,这里其实做了一次contain操作,注释见contain          for (int i = level; i >= 0; i--) {              while (x.forward[i] != null                      && x.forward[i].value.compareTo(value) < 0) {                  x = x.forward[i];              }              //update[i]是比value小的数里面最大的,是value的前置节点              update[i] = x;          }          x = x.forward[0];            //此处不允许插入相同元素,为一个set          if (x == null || !x.value.equals(value)) {//跳表中不包含所要插的元素              //随机产生插入的层级              int lvl = randomLevel();              //产生的随机层级比当前跳表的最高层级大,需要添加相应的层级,并更新最高层级              if (lvl > level) {                  for (int i = level + 1; i <= lvl; i++) {                      update[i] = header;                  }                  level = lvl;              }                            //生成新节点              x = new SkipNode<E>(lvl, value);              //调整节点的指针,和指向它的指针              for (int i = 0; i <= lvl; i++) {                  x.forward[i] = update[i].forward[i];                  update[i].forward[i] = x;              }            }      }      /**      * 删除一个元素      * @param value 待删除值      */      @SuppressWarnings("unchecked")      public void delete(E value) {          SkipNode<E> x = header;          SkipNode<E>[] update = new SkipNode[MAX_LEVEL + 1];          //查找元素的位置,这里其实做了一次contain操作,注释见contain          for (int i = level; i >= 0; i--) {              while (x.forward[i] != null                      && x.forward[i].value.compareTo(value) < 0) {                  x = x.forward[i];              }              update[i] = x;          }          x = x.forward[0];          //删除元素,调整指针          if (x.value.equals(value)) {              for (int i = 0; i <= level; i++) {                  if (update[i].forward[i] != x)                      break;                  update[i].forward[i] = x.forward[i];              }              //如果元素为本层最后一个元素,则删除同时降低当前层级              while (level > 0 && header.forward[level] == null) {                  level--;              }            }      }      /**      * 查找是否包含此元素      * @param searchValue 带查找值      * @return true:包含;false:不包含      */      public boolean contains(E searchValue) {          SkipNode<E> x = header;          //从开始节点的最高层级开始查找          for (int i = level; i >= 0; i--) {              //当到达本层级的NULL节点或者遇到比查找值大的节点时,转到下一层级查找              while (x.forward[i] != null                      && x.forward[i].value.compareTo(searchValue) < 0) {                  x = x.forward[i];              }          }          x = x.forward[0];          //此时x有三种可能,1.x=null,2.x.value=searchValue,3.x.value>searchValue          return x != null && x.value.equals(searchValue);      }      /**      * 这里是跳表的精髓所在,通过随机概率来判断节点的层级      * @return 节点的层级      */      public static int randomLevel() {          int lvl = (int) (Math.log(1. - Math.random()) / Math.log(1. - P));          return Math.min(lvl, MAX_LEVEL);      }        /**      * 输出跳表的所有元素      * 遍历最底层的元素即可      */      public String toString() {          StringBuilder sb = new StringBuilder();          sb.append("{");          SkipNode<E> x = header.forward[0];          while (x != null) {              sb.append(x.value);              x = x.forward[0];              if (x != null)                  sb.append(",");          }          sb.append("}");          return sb.toString();      }  }  


以上是跳跃表在java里的实现


原创粉丝点击