跳躍表實現與原理

/** 
 *  跳錶節點數據存儲結構 
 */  
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裏的實現


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章