简单跳跃表的实现

Java中的跳跃表

Java API中提供了支持并发操作的跳跃表ConcurrentSkipListSet和ConcurrentSkipListMap。下面摘录”Java多线程(四)之ConcurrentSkipListMap深入分析“中的一些结论。
有序的情况下:
1. 在非多线程的情况下,应当尽量使用TreeMap(红黑树实现)。
2. 对于并发性相对较低的并行程序可以使用Collections.synchronizedSortedMap将TreeMap进行包装,也可以提供较好的效率。但是对于高并发程序,应当使用ConcurrentSkipListMap。
无序情况下:
3. 并发程度低,数据量大时,ConcurrentHashMap 存取远大于ConcurrentSkipListMap。
4. 数据量一定,并发程度高时,ConcurrentSkipListMap比ConcurrentHashMap效率更高。

算法参考
增删查改的时间复杂度都与高度相关(0(logn))

实现代码

package org.kelab.skiplist;

import lombok.Data;

/**
 * Created by hongfei.whf on 2017/5/10.
 */
@Data
public class SkipListNode<T> {

    public static final int HEAD_KEY = Integer.MAX_VALUE;
    public static final int TAIL_KEY = Integer.MAX_VALUE;

    private int key;
    private T value;

    private SkipListNode<T> up, down, left, right;

    public SkipListNode(int key, T value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof SkipListNode)) return false;
        if (!super.equals(o)) return false;

        SkipListNode<?> that = (SkipListNode<?>) o;

        if (key != that.key) return false;
        return value != null ? value.equals(that.value) : that.value == null;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + key;
        result = 31 * result + (value != null ? value.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return key + "-" + value;
    }
}
package org.kelab.skiplist;

import lombok.Data;

import java.util.Random;

/**
 * Created by hongfei.whf on 2017/5/10.
 */
@Data
public class SkipList<T> {

    private SkipListNode<T> head, tail;
    private int nodes;
    private int levels;
    private Random rand;
    private static final double PROBABILITY = 0.5;

    /**
     * 构建跳跃表
     */
    public SkipList() {
        this.rand = new Random();
        clear();
    }

    /**
     * 是否为空跳跃表
     *
     * @return
     */
    public boolean isEmpty() {
        return nodes == 0;
    }

    /**
     * 跳跃表大小
     *
     * @return
     */
    public int size() {
        return nodes;
    }

    /**
     * 清空跳跃表
     */
    public void clear() {
        this.head = new SkipListNode<T>(SkipListNode.HEAD_KEY, null);
        this.tail = new SkipListNode<T>(SkipListNode.TAIL_KEY, null);
        this.levels = this.nodes = 0;
        left2right(this.head, this.tail);
    }

    /**
     * 左->右连接
     *
     * @param node1
     * @param node2
     */
    public void left2right(SkipListNode<T> node1, SkipListNode<T> node2) {
        node1.setRight(node2);
        node2.setLeft(node1);
    }

    /**
     * 上->下连接
     *
     * @param node1
     * @param node2
     */
    public void up2down(SkipListNode<T> node1, SkipListNode<T> node2) {
        node1.setDown(node2);
        node2.setUp(node1);
    }

    /**
     * 查找是否存在key结点,若存在返回value,
     * 否则返回前一个位置的节点
     *
     * @param key
     * @return
     */
    private SkipListNode<T> find(int key) {
        SkipListNode<T> p = this.head;
        while (true) {
            while (p.getRight().getKey() != SkipListNode.TAIL_KEY
                    && p.getRight().getKey() <= key) {
                p = p.getRight();
            }
            if (p.getDown() != null) {
                p = p.getDown();
            } else {
                break;
            }
        }
        return p;
    }

    /**
     * 查询是否存在key,存在返回value,否则返回null
     *
     * @param key
     * @return
     */
    public SkipListNode<T> search(int key) {
        SkipListNode<T> p = this.find(key);
        if (p.getKey() == key) {
            return p;
        } else {
            return null;
        }
    }

    /**
     * 跳跃表插入操作
     *
     * @param key
     * @param value
     */
    public void put(int key, T value) {
        SkipListNode<T> p = find(key);
        if (p.getKey() == key) {
            // 替换最底层节点
            p.setValue(value);
            // 如果存在上层节点,一样替换
            SkipListNode up = p.getUp();
            while (up != null) {
                up.setValue(value);
                up = up.getUp();
            }
            return;
        }
        SkipListNode q = new SkipListNode(key, value);
        append(p, q);
        int currLevel = 0;
        // 概率1/2:是否往上加节点
        while (this.rand.nextDouble() < PROBABILITY) {
            // 如果超出高度,新建一层
            if (currLevel >= this.levels) {
                this.levels++;
                // 新建一层
                SkipListNode<T> p1 = new SkipListNode<T>(SkipListNode.HEAD_KEY, null);
                SkipListNode<T> q1 = new SkipListNode<T>(SkipListNode.TAIL_KEY, null);
                left2right(p1, q1);
                // 连接顶层和新建的一层
                up2down(p1, this.head);
                up2down(q1, this.tail);
                this.head = p1;
                this.tail = q1;
            }
            // 将p移到上层节点
            while (p.getUp() == null) {
                p = p.getLeft();
            }
            p = p.getUp();

            // 在上层比起小的节点后面,添加节点
            SkipListNode<T> e = new SkipListNode<>(key, value);
            append(p, e);
            up2down(e, q);
            q = e;
            currLevel++;
        }
        nodes++;
    }

    /**
     * 跳跃表删除操作
     *
     * @param key
     */
    public void remove(int key) {
        SkipListNode<T> p = find(key);
        if (p.getKey() == key) {
            // 删除最底层及其上面的结点
            SkipListNode up = p.getUp();
            remove(p);
            while (up != null) {
                remove(up);
                up = up.getUp();
            }
            nodes--;
            // 清除空层
            while (head.getRight().getKey() == SkipListNode.TAIL_KEY) {
                head = head.getDown();
                levels--;
            }
            return;
        }
    }

    /**
     * node1 后面紧跟着插入node2
     * node<->node3 ==> node<->node2<->node3
     *
     * @param node1
     * @param node2
     */
    private void append(SkipListNode node1, SkipListNode node2) {
        node2.setLeft(node1);
        node2.setRight(node1.getRight()/*node3*/);
        node1.getRight()/*node3*/.setLeft(node2);
        node1.setRight(node2);
    }

    /**
     * 删除node节点
     * node1<->node<->node2 ==> node1<->node2
     *
     * @param node
     */
    private void remove(SkipListNode node) {
        SkipListNode node1 = node.getLeft();
        SkipListNode node2 = node.getRight();
        left2right(node1, node2);
    }

    /**
     * 打印出原始数据
     */
    @Override
    public String toString() {
        if (isEmpty()) {
            return "跳跃表为空!";
        }
        StringBuilder builder = new StringBuilder();
        SkipListNode<T> p = head;
        int plevels = levels;
        while (plevels-- >= 0) {
            SkipListNode<T> q = p.getDown();
            boolean isFirst = true;
            while (p.getRight() != null) {
                if (isFirst) {
                    isFirst = false;
                } else {
                    builder.append(" <=> ");
                }
                builder.append(p.toString());
                p = p.getRight();
            }
            builder.append("\n");
            p = q;
        }
        return builder.toString();
    }

    public static void main(String[] args) {
        SkipList<String> list = new SkipList<String>();
        System.out.println(list);
        list.put(2, "a");
        list.put(1, "b");
        list.put(3, "c");
        list.put(1, "d");//测试同一个key值
        System.out.println(list.getLevels());
        System.out.println(list);
        System.out.println("====");
        list.remove(2);
        System.out.println(list);
        System.out.println(list.size());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值