跳跃表实现与原理

/** 
 *  跳表节点数据存储结构 
 */  
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里的实现


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值