2009-12-10 3 views
0

Мне нужна эффективная структура Java для управления очень разреженными векторами двойников: основные операции чтения/записи. Я реализовал его в HashMap, но доступ слишком медленный. Должен ли я использовать другую структуру данных? Вы рекомендуете какую-либо бесплатную библиотеку?Java-эффективный разреженный массив 1D (double)

Глядя на некоторые советы мирного :)

Спасибо большое,

Мари

+2

Доступ к HashMap слишком медленный? Я знаю, что есть накладные расходы с использованием HashMap, но это только вызов ваших методов hashCode и equals. Вы убедились, что эти методы имеют оптимальную реализацию? – Malaxeur

+0

Какой доступ вам нужен, чтобы быть быстрым? Трудно поверить, что HashMap вызывает много накладных расходов над гипотетическим оптимальным решением, если ваши индексы не имеют хеша должным образом ... –

+1

@pascal HashMap помещает все индексы в объекты Integer, это ** ** медленно. – akuhn

ответ

3

HashMap это путь. Это не должно быть медленным. Запустите свой код через профилировщик, чтобы увидеть, где все время идет, а затем оптимизируйте соответствующим образом. Если вам нужны советы по оптимизации кода, отправьте здесь пример, чтобы мы могли помочь с конкретной проблемой.

[EDIT] В зависимости от размера индексов вы можете использовать технику, как в Integer.valueOf(int), для кэширования объектов для бокса. Но это будет работать только при создании большого количества карт, а индексы находятся в несколько ограниченном диапазоне.

Или вы можете попробовать IntHashMap от commons-lang. Это немного сложно использовать (это частный пакет), но вы можете скопировать код.

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

+0

ОК, спасибо всем за ваш быстрый ответ. Из ваших ответов я понимаю, что HashMap - лучшая стратегия для использования. На самом деле, я использую *** очень большие данные, которые, к сожалению, не могу оптимизировать, и мне было интересно, как сделать мой код более эффективным. :) Еще раз спасибо! – Marie

+0

OP говорит, что карта слишком медленная, извините, но чтение Q должно быть минимальным, прежде чем отвечать. – akuhn

+0

@Adrian: И чтение моего ответа должно быть минимальным, прежде чем сбрасывать его. –

0

Вы можете копировать вставить разреженный вектор из моего проекта Hapax: ch.akuhn.matrix.SparseVector

PS: на все другие ответы и комментарии, которые Dont почему использование обращали внимание на карту слишком медленно. Он медленный, потому что карта помещает все индексы в объекты Integer!

Редкий вектор, представленный здесь, является быстрым для чтения и добавления значений, но не для случайных индексов. Это оптимально для сценария, в котором вы сначала создаете вектор смены, но добавляете значения в порядке возрастания индексов, а затем используете карту для чтения в основном.

Важные методы в разреженном векторе классе

// ... 

public class SparseVector { 

    /*default*/ int[] keys; 
    /*default*/ int size, used; 
    /*default*/ double[] values; 

    public SparseVector(int size, int capacity) { 
     assert size >= 0; 
     assert capacity >= 0; 
     this.size = size; 
     this.keys = new int[capacity]; 
     this.values = new double[capacity]; 
    } 

    public double get(int key) { 
     if (key < 0 || key >= size) throw new IndexOutOfBoundsException(Integer.toString(key)); 
     int spot = Arrays.binarySearch(keys, 0, used, key); 
     return spot < 0 ? 0 : values[spot]; 
    } 

    public boolean isUsed(int key) { 
     return 0 <= Arrays.binarySearch(keys, 0, used, key); 
    } 

    public double put(int key, double value) { 
     if (key < 0 || key >= size) throw new IndexOutOfBoundsException(Integer.toString(key)); 
     int spot = Arrays.binarySearch(keys, 0, used, key); 
     if (spot >= 0) return values[spot] = (float) value; 
     else return update(-1 - spot, key, value); 
    } 

    public void resizeTo(int newSize) { 
     if (newSize < this.size) throw new UnsupportedOperationException(); 
     this.size = newSize; 
    } 

    public int size() { 
     return size; 
    } 

    private double update(int spot, int key, double value) { 
     // grow if reaching end of capacity 
     if (used == keys.length) { 
      int capacity = (keys.length * 3)/2 + 1; 
      keys = Arrays.copyOf(keys, capacity); 
      values = Arrays.copyOf(values, capacity); 
     } 
     // shift values if not appending 
     if (spot < used) { 
      System.arraycopy(keys, spot, keys, spot + 1, used - spot); 
      System.arraycopy(values, spot, values, spot + 1, used - spot); 
     } 
     used++; 
     keys[spot] = key; 
     return values[spot] = (float) value; 
    } 

    public int used() { 
     return used; 
    } 

    public void trim() { 
     keys = Arrays.copyOf(keys, used); 
     values = Arrays.copyOf(values, used); 
    } 

} 
+0

ОК, спасибо, это кажется очень приятным. Возникает вопрос: стала ли эта реализация более эффективной с точки зрения времени, чем HashMap? Я действительно не эксперт ... давайте голосовать (но, пожалуйста, не драться) – Marie

+0

Ввод может быть медленнее, получение будет быстрее. Я добавлю это к ответу. – akuhn

+0

Голосовать ?? Мера! – Svante

0

Для 1D разреженного массива, карта, как правило, путь. Вам нужно всего лишь использовать библиотеку, если она многомерна.

Если сравнить время доступа между картой и массив,

map.get(99); 
    array[99]; 

карта будет гораздо медленнее. У любой библиотеки будет такая же проблема.

Разве это разреженный массив? Вы торгуете временем для космоса.

+1

OP говорит, что карта слишком медленная, извините, но чтение Q должно быть минимальным, прежде чем отвечать. – akuhn

+3

Чтение A должно быть минимальным значением перед downvoting :( –

+0

. Ваш ответ не предполагает, что другая структура данных не является библиотекой. ОП попросил об этом. Если вы исправите это, я удалю нижний предел. – akuhn

1

Насколько велик ваш набор данных? Значительно больше Integer.MAX_VALUE? проблема в том, что HashSet поддерживается массивом. Столкновения замедляют работу. Возможно, что механизм hashmap не слишком медленный, но тот факт, что у вас много столкновений. Возможно, если вы сначала разделили свои данные (например, используя другую хеш-функцию), затем сохранили каждый раздел данных в собственном хэш-файле, который вам повезет больше.

Смежные вопросы