Оптимизация реализации списка пропуска Java

Я борюсь с реализацией списка пропусков в java. В основном все работает нормально, но метод put выполняется слишком долго. Вот мой код, я просмотрел учебные пособия и просмотрел коды некоторых людей, и я, кажется, не вижу, в чем проблема (если вы измеряете размещение 100000 случайных элементов, для работы требуются годы).

public class SkipList<K,V> {

    private final SkipListItem<K,V> head;
    private int currentLevel = 0;
    private static final Random random = new Random();
    private int height = 0;

    public SkipList() {
        this.head = new SkipListItem<>(null, null);
    }

    public V put(K key, V value) {
        return this.put(key, value, null, 0);
    }

    private V put(K key, V value, SkipListItem<K,V> previous, int level) {
        if(level > this.height) {
            for(int i=0,s=level-this.height ; i<s ; ++i) {
                this.addHeadItem();
            }
        }
        SkipListItem<K,V> addedItem = new SkipListItem<>(key, value);
        SkipListItem<K,V> insertAfter = this.findLowerItem(key, level);
        addedItem.setPrevious(insertAfter);
        if(insertAfter.getNext() != null) {
            insertAfter.getNext().setPrevious(addedItem);
            addedItem.setNext(insertAfter.getNext());
        }
        insertAfter.setNext(addedItem);
        if(previous != null) {
            addedItem.setBelow(previous);
            previous.setAbove(addedItem);
        }

        return (SkipList.random.nextBoolean()) ? this.put(key, value, addedItem, level+1) : value ;
    }

    private void addHeadItem() {
        SkipListItem<K,V> item = this.head;
        while(item.getAbove() != null) {
            item = item.getAbove();
        }
        SkipListItem<K,V> newHead = new SkipListItem<>(null,null);
        item.setAbove(newHead);
        newHead.setBelow(item);
        ++this.height;
    }

    private SkipListItem<K,V> findLowerItem(K key) {
        return this.findLowerItem(key,0);
    }

    private SkipListItem<K,V> findLowerItem(K key, int level) {
        SkipListItem<K,V> currentItem = this.head;
        for(int i=0 ; i<level ; ++i) {
            currentItem = currentItem.getAbove();
        }
        while(  currentItem.getNext() != null &&
                currentItem.getNext().getKey() != null &&
                currentItem.getNext().compareTo(key) < 0) {
            currentItem = currentItem.getNext();
        }
        return currentItem;
    }
    //...some other functions...
}

есть идеи, почему так долго?


person kcdsh    schedule 26.11.2015    source источник
comment
Сделайте профилирование некоторых методов. Что так долго? (stackoverflow.com/questions/2267594/ или некоторую ручную System.nanoTime() агрегацию)   -  person zapl    schedule 26.11.2015
comment
Можете ли вы включить код для SkipListItem?   -  person Paul Boddington    schedule 26.11.2015
comment
Пробовали ли вы пошаговую отладку, чтобы убедиться, что put() ведет себя так, как задумано (т. е. ищет с использованием индекса, а не списка 0-го уровня, и правильно строит индекс)?   -  person Alex Salauyou    schedule 26.11.2015
comment
Во всяком случае, если посмотреть глубже, кажется, что вы вообще не используете индекс для операций put() - когда level = 0, верхние уровни не задействованы. Чтобы заставить его работать, findLowerItem() должен сначала искать на верхнем уровне (уровень = высота), затем все ниже и ниже, пока не будет достигнут заданный уровень.   -  person Alex Salauyou    schedule 26.11.2015


Ответы (1)


На первый взгляд, всякий раз, когда вы вставляете новый элемент, вы потенциально просматриваете весь список, чтобы найти позицию. Это приводит к линейной сложности, поэтому для вставки n элементов требуется n*n операций.

В частности, в вашем случае окончательное число составляет 10 миллиардов операций, которые уже довольно сложны, поэтому я могу представить, что это займет несколько минут для заполнения.

person Zbynek Vyskovsky - kvr000    schedule 26.11.2015