All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.cheny.toolbox.other.skiplist.SkipList Maven / Gradle / Ivy

There is a newer version: 2.3.6-jdk8
Show newest version
package cn.cheny.toolbox.other.skiplist;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.util.Random;

/**
 * 数据结构:跳表
 *
 * @author cheney
 */
public class SkipList> {

    /**
     * 默认层数
     */
    protected static final int DEFAULT_MAX_HIGH = 32;

    /**
     * 第0层头节点
     */
    private Node head;

    /**
     * 第0层尾节点
     */
    private Node tail;

    private int size;

    private int high;

    private final int maxHigh;

    protected static class Node> {

        private final int high;

        private T value;

        private Node pre;

        private Node[] next;

        @SuppressWarnings("unchecked")
        Node(T value, int high) {
            this.value = value;
            this.high = high;
            this.next = new Node[high];
        }

        public T getValue() {
            return value;
        }

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

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node[] getNext() {
            return next;
        }

        public void setNext(Node[] next) {
            this.next = next;
        }

        public void setNext(Node next, int high) {
            this.next[high] = next;
        }

        public int getHigh() {
            return high;
        }

        public void clear() {
            this.value = null;
            this.next = null;
            this.pre = null;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;

            if (o == null || getClass() != o.getClass()) return false;

            Node node = (Node) o;

            return new EqualsBuilder().append(high, node.high).append(value, node.value).isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37).append(high).append(value).toHashCode();
        }

        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    '}';
        }
    }

    public SkipList() {
        this(DEFAULT_MAX_HIGH);
    }

    public SkipList(int maxHigh) {
        if (maxHigh <= 1) {
            throw new IllegalArgumentException("illegal arg max high,must gt 1");
        }
        this.maxHigh = maxHigh;
        init();
    }

    private void init() {
        this.size = this.high = 0;
        // 初始化head
        this.head = new Node<>(null, this.maxHigh);
    }

    /**
     * 往跳表新增值
     *
     * @param value 新增值
     */
    public void add(T value) {
        if (value == null) {
            throw new IllegalArgumentException("value can not be null");
        }
        int level = randomLevel();
        Node n = new Node<>(value, level);
        Node cur = this.head;
        for (int i = level - 1; i >= 0; i--) {
            Node next;
            while ((next = cur.getNext()[i]) != null &&
                    next.value.compareTo(value) <= 0) {
                cur = next;
            }
            if (cur.value != null && cur.value.compareTo(value) == 0
                    && replaceWhileExists()) {
                cur.value = value;
                return;
            }
            // 新节点插入到update之后,originNext之前
            Node originNext = cur.getNext()[i];
            n.setNext(originNext, i);
            cur.setNext(n, i);
        }
        // 更新pre,tail
        n.setPre(cur);
        Node next = n.getNext()[0];
        if (next == null) {
            this.tail = n;
        } else {
            next.setPre(n);
        }
        // 更新high,size
        if (level > this.high) {
            this.high = level;
        }
        size++;
    }

    /**
     * 通过调表查询与入参值相等的数据
     *
     * @param target 查找的数据
     * @return 是否存在
     */
    public T get(T target) {
        Node node = getNode(target);
        return node == null ? null : node.getValue();
    }

    /**
     * 通过调表查询与入参值相等的数据,不存在时返回其上一个数据
     *
     * @param target 查找的数据
     * @return 是否存在
     */
    public T getTargetOrPre(T target) {
        Node node = getTargetOrPreNode(target);
        return node == null ? null : node.getValue();
    }

    /**
     * 通过调表查询是否存在数据
     *
     * @param target 查找的数据
     * @return 是否存在
     */
    public boolean contains(T target) {
        return getNode(target) != null;
    }

    /**
     * 删除所有与目标数据相同的节点
     *
     * @param target 删除的数据值
     * @return 是否执行删除
     */
    public boolean remove(T target) {
        if (target == null) {
            throw new IllegalArgumentException("value can not be null");
        }
        boolean flag = false;
        int curLevel = high - 1;
        Node cur = head;
        while (curLevel >= 0) {
            Node next;
            while ((next = cur.getNext()[curLevel]) != null) {
                int compare = next.value.compareTo(target);
                if (compare < 0) {
                    cur = next;
                } else if (compare == 0) {
                    // remove next
                    Node delNext = next.getNext()[curLevel];
                    if (delNext != null && delNext.pre == next) {
                        delNext.setPre(cur);
                    }
                    cur.setNext(delNext, curLevel);
                    flag = true;
                } else {
                    break;
                }
            }
            curLevel--;
        }
        return flag;
    }

    /**
     * 查找与目标数据相同的节点,然后找出其偏移量为offset的数据
     *
     * @param target 删除的数据值
     * @return 是否执行删除
     */
    public T offset(T target, int offset) {
        Node targetOrPreNode = getTargetOrPreNode(target);
        if (targetOrPreNode == null) {
            return null;
        }
        int curOffset = offset;
        Node offsetNode = targetOrPreNode;
        while (curOffset != 0 && offsetNode != null) {
            if (curOffset > 0) {
                offsetNode = offsetNode.getNext()[0];
                curOffset--;
            } else {
                if (curOffset != -1) {
                    offsetNode = offsetNode.pre;
                }
                curOffset++;
            }
        }
        return offsetNode == null ? null : offsetNode.value;
    }

    /**
     * 返回跳表长度
     *
     * @return 跳表长度
     */
    public int size() {
        return size;
    }

    /**
     * 通过跳表查询数据
     *
     * @param target 查找的数据
     * @return 数据节点
     */
    protected Node getNode(T target) {
        Node targetOrPreNode = getTargetOrPreNode(target);
        if (targetOrPreNode == null || targetOrPreNode.value.compareTo(target) != 0) {
            return null;
        }
        return targetOrPreNode;
    }

    /**
     * 通过跳表查询数据,不存在时返回其上一个节点
     *
     * @param target 查找的数据
     * @return 数据节点
     */
    protected Node getTargetOrPreNode(T target) {
        if (target == null) {
            return null;
        }
        int curLevel = high - 1;
        Node cur = head;
        while (curLevel >= 0) {
            Node next;
            while ((next = cur.getNext()[curLevel]) != null) {
                int compare = next.value.compareTo(target);
                if (compare < 0) {
                    cur = next;
                } else if (compare == 0) {
                    return next;
                } else {
                    break;
                }
            }
            curLevel--;
        }
        return cur;
    }

    /**
     * 存在时是否替换
     *
     * @return 默认返回false
     */
    protected boolean replaceWhileExists() {
        return false;
    }

    /**
     * 抛硬币,每抛一次正面增加一层
     * 最大MAX_HIGH层
     *
     * @return 层级
     */
    private int randomLevel() {
        Random random = new Random();
        int level = 1;
        int maxHigh = this.maxHigh;
        for (int i = 1; i < maxHigh; i++) {
            if ((random.nextInt(2) & 1) == 1) {
                level++;
            }
        }
        return level;
    }

    @Override
    public String toString() {
        StringBuilder print = new StringBuilder();
        for (int i = high - 1; i >= 0; i--) {
            if (i == 0) {
                print.append("head--->");
            } else {
                print.append("\t\t");
            }
            Node cur = this.head;
            int l = print.length();
            while ((cur = cur.getNext()[i]) != null) {
                print.append(cur.value).append("-----");
            }
            if (print.length() > l) {
                print.setLength(print.length() - 5);
            }
            if (i == 0) {
                print.append("--->tail");
            } else {
                print.append("\r\n");
            }
        }
        return print.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy