跳跃表--Java实现

x33g5p2x  于2021-11-19 转载在 Java  
字(4.6k)|赞(0)|评价(0)|浏览(274)

源文来自这里:https://www.cnblogs.com/shoshana-kong/p/10798489.html

原理就不多说了,网上有很多介绍的。这里直接上代码。

SkipListNode

public class SkipListNode<T> {
    public int             key;
    public T               value;
    public SkipListNode<T> pre, next, up, down; //上下左右四个节点,pre和up存在的意义在于 "升层"的时候需要查找相邻节点

    public static final int HEAD_KEY = Integer.MIN_VALUE; // 负无穷
    public static final int TAIL_KEY = Integer.MAX_VALUE; // 正无穷

    public SkipListNode(int k, T v) {
        key = k;
        value = v;
    }

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        if (!(o instanceof SkipListNode<?>)) {
            return false;
        }
        SkipListNode<T> ent;
        try {
            ent = (SkipListNode<T>) o; //检测类型
        } catch (ClassCastException ex) {
            return false;
        }
        return (ent.getKey() == key) && (ent.getValue() == value);
    }

    @Override
    public String toString() {
        return "key-value:" + key + "," + value;
    }
}

SkipList

import java.util.Random;

public class SkipList<T> {
    private SkipListNode<T> head, tail;
    private              int    size;
    private              int    listLevel;
    private              Random random;
    private static final double PROBABILITY = 0.5;

    public SkipList() {
        head = new SkipListNode<>(SkipListNode.HEAD_KEY, null);
        tail = new SkipListNode<>(SkipListNode.TAIL_KEY, null);
        head.next = tail;
        tail.pre = head;
        size = 0;
        listLevel = 0;
        random = new Random();
    }

    public SkipListNode<T> get(int key) {
        SkipListNode<T> p = findNode(key);
        if (p.key == key) {
            return p;
        }
        return null;
    }

    //首先查找到包含key值的节点,将节点从链表中移除,接着如果有更高level的节点,则repeat这个操作即可。
    public T remove(int k) {
        SkipListNode<T> p = get(k);
        if (p == null) {
            return null;
        }
        T oldV = p.value;
        SkipListNode<T> q;
        while (p != null) {
            q = p.next;
            q.pre = p.pre;
            p.pre.next = q;
            p = p.up;
        }
        return oldV;
    }

    /**
     * put方法有一些需要注意的步骤:
     * 1.如果put的key值在跳跃表中存在,则进行修改操作;
     * 2.如果put的key值在跳跃表中不存在,则需要进行新增节点的操作,并且需要由random随机数决定新加入的节点的高度(最大level);
     * 3.当新添加的节点高度达到跳跃表的最大level,需要添加一个空白层(除了-oo和+oo没有别的节点)
     *
     * @param k
     * @param v
     */
    public void put(int k, T v) {
        System.out.println("添加key:" + k);
        SkipListNode<T> p = findNode(k);//这里不用get是因为下面可能用到这个节点
        System.out.println("找到P:" + p);
        if (p.key == k) {
            p.value = v;
            return;
        }

        SkipListNode<T> q = new SkipListNode<>(k, v);
        insertNode(p, q);

        int currentLevel = 0;
        while (random.nextDouble() > PROBABILITY) {
            if (currentLevel >= listLevel) {
                addEmptyLevel();
                System.out.println("升层");
            }
            while (p.up == null) {
                System.out.println(p);
                p = p.pre;
                System.out.println("找到第一个有上层结点的值" + p);
            }
            p = p.up;
            //创建 q的镜像变量(只存储k,不存储v,因为查找的时候会自动找最底层数据)
            SkipListNode<T> z = new SkipListNode<>(k, null);
            insertNode(p, z);
            z.down = q;
            q.up = z;
            //别忘了把指针移到上一层。
            q = z;
            currentLevel++;
            System.out.println("添加后" + this);

        }
        size++;

    }

    /**
     * 如果传入的key值在跳跃表中不存在,则findNode返回跳跃表中key值小于key,并且key值相差最小的底层节点;
     * 所以不能用此方法来代替get
     *
     * @param key
     * @return
     */
    public SkipListNode<T> findNode(int key) {
        SkipListNode<T> p = head;
        while (true) {
            System.out.println("p.next.key:" + p.next.key);
            if (p.next != null && p.next.key <= key) {
                p = p.next;
            }
            System.out.println("找到node:" + p);
            if (p.down != null) {
                System.out.println("node.down :" + p);
                p = p.down;
            } else if (p.next != null && p.next.key > key) {
                break;
            }
        }
        return p;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public void addEmptyLevel() {
        SkipListNode<T> p1 = new SkipListNode<T>(SkipListNode.HEAD_KEY, null);
        SkipListNode<T> p2 = new SkipListNode<T>(SkipListNode.TAIL_KEY, null);
        p1.next = p2;
        p1.down = head;
        p2.pre = p1;
        p2.down = tail;
        head.up = p1;
        tail.up = p2;
        head = p1;
        tail = p2;
        listLevel++;
    }

    private void insertNode(SkipListNode<T> p, SkipListNode<T> q) {
        q.next = p.next;
        q.pre = p;
        p.next.pre = q;
        p.next = q;
    }

    public int getLevel() {
        return listLevel;
    }

    @Override
    public String toString() {
        SkipListNode<T> down = head.down;
        while (down != null && down.down != null) {
            down = down.down;
        }
        StringBuilder sb = new StringBuilder("SkipList{");
        while (down != null && down.next != null) {
            if (down.key > -1) {
                sb.append("(").append(down.key).append(",").append(down.value).append("),");
            }
            down = down.next;
        }
        sb.deleteCharAt(sb.length() - 1);
        sb.append("}");
        return sb.toString();
    }
}

测试

public class SkipListTest {
    public static void main(String[] args) {
        SkipList<String> list = new SkipList<>();
        list.put(10, "sho");
        list.put(1, "sha");
        list.put(9, "na");
        list.put(2, "bing");
        list.put(8, "ling");
        list.put(7, "xiao");
        list.put(100, "你好,skiplist");
        list.put(5, "冰");
        list.put(6, "灵");
        System.out.println("列表元素:\n" + list);
        System.out.println("删除100:" + list.remove(100));
        System.out.println("列表元素:\n" + list);
        System.out.println("5对于的value:\n" + list.get(5).value);
        System.out.println("链表大小:" + list.size() + ",深度:" + list.getLevel());
    }
}

相关文章

微信公众号

最新文章

更多