2012-02-13 2 views
9

Я пытаюсь найти, есть ли хороший способ поиска (подсчитать количество вхождений), а затем отсортировать массив строк эффективным образом ... это способ, который будет хорошо работать во встроенных системах (32Mb)Каков наилучший способ подсчета и сортировки строкового массива

Пример: Я должен подсчитать количество времени, символ а, в, с, и т.д. ... используется кроме того, что результат для задней сортировки ...

я могу рассчитывать, используя подсчет общественного ИНТА (String searchDomain, символ searchValue) метод, но каждая строка должна иметь всю букву алфавита, например:

"This is a test string" 
A:1,B:0,C:0,D:0,E:1,I:3,F:0,... 
"ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC" 
A:7,B:0,C:22,G:18 

Мой метод сортировки должны быть в состоянии ответить на такие вещи, как: Сортировать по количеству As, Bs рода сначала As, а затем сортировать, что поддомен Б.С.

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

+0

Если вы имеете дело с большим количеством данных, чем вы можете поместиться в память сразу, у слияния есть хорошие характеристики io – chucksmash

+2

Можете ли вы показать нам свою текущую реализацию? Возможно, было бы проще оптимизировать вашу текущую реализацию, чем начинать с нуля. –

+0

Мне жаль, что я не код, но код не мой для публикации, но в основном это сочетание словаря с hashmap ... он работает нормально, но он имеет огромный размер, что делает его непригодным для мобильных устройств ... Я думаю, возможно, было бы лучше всего сохранить все это на сервере, но мне нужно иметь возможность сортировать его по поддоменам ... – Astronaut

ответ

11

Я бы воспользовался Java (очень эффективным), встроенным в функции сортировки. Начнем с того, определить простой класс, чтобы содержать вашу строку и метаданные:

class Item 
{ 
    // Your string. It's public, so you can get it if you want, 
    // but also final, so you can't accidentally change it. 
    public final String string; 

    // An array of counts, where the offset is the alphabetical position 
    // of the letter it's counting. (A = 0, B = 1, C=2...) 
    private final short[] instanceCounts = new short[32]; 

    public Item(String string) 
    { 
     this.string = string; 
     for(char c : string.toCharArray()) 
     { 
      // Increment the count for this character 
      instanceCounts[(byte)c - 65] ++; 
     } 
    } 

    public int getCount(char c) 
    { 
     return instanceCounts[(byte)c - 65]; 
    } 
} 

Это будет держать вашу строку (для поиска и отображения), а также создать массив трусах с кол-согласующих символов. (Если у вас действительно с низким объемом памяти, и вы знаете, что ваши строки имеют более 255 любого символа, вы можете даже изменить это на массив байтов.) Короткий - это всего лишь 16 байт, поэтому сам массив будет возьмите 64 байта вместе независимо от того, насколько сложна ваша строка. Если вы хотите заплатить за хит производительности за вычисление счетчиков каждый раз, вы можете избавиться от массива и заменить метод getCount(), но вы, вероятно, в конечном итоге сохраните единовременную память, потребляя часто-мусор память, которая является большим хитом производительности.:)

Теперь определите правило, которое вы хотите искать, используя Comparator. Например, для сортировки по количеству A-ых в вашей строке:

class CompareByNumberOfA implements Comparator<Item> 
{ 
    public int compare(Item arg0, Item arg1) 
    { 
     return arg1.getCount('A') - arg0.getCount('A'); 
    } 
} 

Наконец, придерживаться всех ваших элементов в массиве, а также использовать встроенный (и очень эффективной памяти) Массивы методов сортировки. Например:

public static void main(String args[]) 
{ 
    Item[] items = new Item[5]; 
    items[0]= new Item("ABC"); 
    items[1]= new Item("ABCAA"); 
    items[2]= new Item("ABCAAC"); 
    items[3]= new Item("ABCAAA"); 
    items[4]= new Item("ABBABZ"); 

    // THIS IS THE IMPORTANT PART! 
    Arrays.sort(items, new CompareByNumberOfA()); 

    System.out.println(items[0].string); 
    System.out.println(items[1].string); 
    System.out.println(items[2].string); 
    System.out.println(items[3].string); 
    System.out.println(items[4].string); 
} 

Вы можете определить целую кучу компараторов и использовать их как вам нравится.

Одна из вещей, которые нужно запомнить о кодировании с помощью Java, - это не слишком умно. Составители делают чертовски прекрасную работу по оптимизации своей платформы, до тех пор, пока вы воспользуетесь вещами, которые может оптимизировать (например, встроенные API, включая Array.sort).

Часто, если вы пытаетесь стать слишком умным, вы просто оптимизируете себя из эффективного решения. :)

+0

Это решение в значительной степени похоже на то, что у меня есть на данный момент, мой вопрос для вас был бы, если бы был более компактный способ хранения letterIndexByteArray, то есть способ хранения результатов поиска, поэтому мне не нужно его пересчитывать , за исключением таблицы поиска, которую я пришла с пустыми руками в этом отношении ... с большой доменой строки это потребует большого количества сравнений ... что такое O (x) сортировки Java? – Astronaut

+0

Счетный массив? У вас есть верхняя граница того, сколько персонажей любого типа есть? Вы можете использовать байты, а не шорты, и «unsign» их путем их маскировки в целые числа, когда вы их читаете. Это уменьшает объем необходимой памяти, но прерывается, если у вас есть строка с более чем 255 одного и того же символа. Если это все еще слишком много памяти, вам нужно выровнять таблицу counts и запустить алгоритм поиска по одному проходу по вашим строкам. Для этого мне нужно больше узнать о вашем алгоритме. (И сортировка Java обычно представляет собой сортировку слияния in-situ. Не требуется дополнительной памяти.) – Erica

+0

@Adam Surfari Зачем вам нужно хранить полные строки, которые являются вашими главными поглотителями памяти? В решении Erica, после подсчета, вы можете сохранить строковый идентификатор вместо поля с именем 'string' (короче исходной строки), чтобы вы могли получить строку позже, если вам это нужно. –

0

Я могу помочь с php/псевдокодом и хэш-картами или ассоциативными массивами.

$hash=""; 

$string = "ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC" 
while (read each $char from $string) { 

    if (isset($hash[$char])) { 
     $hash[$char] = $hash[$char]+1 
    } else { 
     $hash[$char]=1 
    } 
} 

в конце концов вы будете иметь ассоциативный массив с 1 ключ/полукокса найдено и хэш-значения вы будете иметь значение счетчика вхождений

Это не PHP (или любой другой язык если на то пошло), но этот принцип должен помочь.

+1

Моя проблема не в том, что касается символов, это больше о создании эффективной структуры данных, которая способна хранить данные подсчета и сортировать по поддоменам или подмножествам ... возможно, мне нужно сделать мой вопрос более ясным? – Astronaut

1

Я считаю, что то, что вам нужно, это древовидная структура, и на самом деле вопрос будет лучше переписан, говоря о древовидной структуре, чтобы индексировать длинную непрерывную строку, а не «считать» или «сортировать».

Я не уверен, что это решение или повторение вопроса. Вам нужна структура данных, которая является деревом, где корень имеет, например. 26 поддеревьев, один для строк, начинающихся с «A», следующего ребенка для «B» и т. Д .; то ребенок «А» имеет, например, 20 детей, представляющих «AB», «AC», «AT» и т. Д .; и так далее до детей, представляющих, например, «ABALXYZQ», где каждый дочерний элемент содержит целое поле, представляющее счетчик, то есть количество раз, когда происходит подстрока?

class AdamTree { 
    char ch; 
    List<AdamTree> children; 
    int count; 
} 

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

+0

Привет, Тим, нет, это не то, что я хочу ... Я не хочу хранить первый символ или подстроку. Я хочу сохранить количество раз, которое имеет этот символ для этих строк, и затем иметь подмножество строк, которые имеют A> 10, то мне нужно иметь возможность запросить это подмножество снова, для B> 20 и т. Д., Пока я не останусь с уменьшенным набором строк. – Astronaut

+0

Итак, возьмите 2: у вас есть набор строк, и вы хотите отвечать на него на запросы, например: сколько (или) строк содержит более 10 A и более 13 B и более 7 C и т. Д.? В каком случае необходимо подсчитать A до B и т. Д.? –

+0

@Adam Surfari: Возьмите 3: вы не знаете, сколько вам нужно, но вы знаете, что хотите взять 100 лучших «строк, которые содержат много A»? И из этого набора вы хотите взять верхние 10 строк, которые содержат много B '? И тогда из этого набора возьмите строку, у которой больше C? –

0

http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm Посмотрите на алгоритм KMP. Это довольно распространенная проблема программирования. Выше вы найдете одно из самых быстрых решений. Легко понять и реализовать.

Подсчитайте вхождения с помощью KMP, затем либо пойдите с сортировкой слияния после вставки, либо если вы знаете, что массив/etc отсортирован, пойдите с бинарным поиском/вставкой направления.

0

Возможно, вы могли бы использовать некую древовидную структуру, где глубина соответствует заданной букве. Таким образом, каждый узел в дереве соответствует букве + счету вхождений этой буквы. Если только одна строка соответствует этому узлу (и его родительским узлам), то он сохраняется в узле. В противном случае узел имеет дочерние узлы для следующих букв и буквы.

Таким образом, это дало бы что-то вроде этого:

A:  0     1     3   ... 
     |    / \   / \ 
B:  0    0  1   1  3 
    /\   heaven / \  barracuda ababab 
C: 0 1     0  1 
    foo cow    bar  bac 

Не уверен, что это будет стоить меньше, чем счетный массив решения, но по крайней мере вы не должны хранить счетчик для всех букв для всех строк (дерево останавливается, когда подсчитывать буква однозначно идентифицирует строку)

Вы могли бы оптимизировать его, сокращая длинные ветви без братьев и сестер

0

Вы могли бы попробовать код в Java ниже

int[] data = new int[254];//we have 254 different characters 
void processData(String mString){ 

    for (int i=0 ; i< mString.length;i++){ 
     char c = mString.charAt(i); 
     data[c]++; 
    } 
} 
int getCountOfChar(char c){ 
    return data[c]; 
} 
1

Извините, у меня нет времени, чтобы написать это лучше. Для того, чтобы свести к минимуму пространство, я бы сделать два м х п (плотные) массивы, один байт и один короткий, где:

  • м является число входных строк
  • п есть число символов в каждой строки; этот размер варьируется от строки к строке
  • массив содержит символ
  • короткий массив содержит счетчик для этого персонажа

Если отсчеты гарантируется < 256, вы можете использовать только один mxnx 2 байтовый массив ,

Если набор символов, которые вы используете, является плотным, то есть множество ВСЕХ символов, используемых в ЛЮБОЙ строке, не намного больше, чем набор символов, используемых в строке КАЖДЫЙ, вы можете избавиться от массива байтов и просто используйте фиксированное «n» (выше) с функцией, которая отображает от символа к индексу. Это будет намного быстрее.

Для этого потребуется 2Q обхода этого массива для любого запроса с предложениями Q. Надеюсь, это будет достаточно быстро.

0

Кажется, есть некоторые путаницы в отношении ваших требований и целей.

Если ваши результаты поиска занимают слишком много места, почему бы не «сжать компресс» (например, сжатие музыки) результаты? Вид вроде хеш-функции. Затем, когда вам нужно получить результаты, ваш хеш указывает гораздо меньшее подмножество строк, которое необходимо искать правильно с помощью более длинного алгоритма поиска.

Если вы на самом деле храните объекты String, и ваши строки на самом деле являются человекообразным текстом, вы можете попытаться сдуть их с помощью java.util.zip после того, как вы закончите поиск и индексирование и все такое. Если вы действительно хотите сохранить их крошечными, и вы не получите фактических String объектов, и вы сказали, что у вас есть только 26 разных букв, вы можете сжать их в группы по 5 бит и сохранить их таким образом. Для этого используйте интерфейс CharSequence.

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