Алгоритм — Нахождение наиболее распространенных k-мер и их количества появлений в переполнении стека

Что касается кмер https://en.wikipedia.org/wiki/K-mer

Я пытаюсь найти наиболее частые k-меры в большом файле fastq. Мой план состоял в том, чтобы использовать алгоритм misra-gries для поиска наиболее частых k-мер, а затем производить поиск каждого частого k-мер в файле со вторым проходом. Но я не думаю, что мой алгоритм достаточно эффективен. Вот мой первый черновик ниже. Я стараюсь максимально эффективно использовать память (программа не должна исчерпывать память)

Я также нашел этот алгоритм DSK, но он слишком сложен для понимания, не видя простой реализации. http://minia.genouest.org/dsk/

Примечание: также ID каждого счетчика будут целыми числами, а не строками, я собираюсь изменить его позже в моем окончательном проекте.

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;

struct node {
string id;
int count;
};

void searchCount(vector <node>&memory, string line,int k) {
int count = 0;
string kMer;
for (int i = 0; i < memory.size(); i++) {
if (memory[i].id != "") {
for (int j = 0; j < line.length() - k + 1; j++) {
kMer = line.substr(j, k);
if (kMer == memory[i].id) {
count++;
}
}
}
memory[i].count = count;
count = 0;
}
}

int doWeHaveSpace(vector <node> memory) {
for (int i = 0; i < memory.size(); i++) {
if (memory[i].id == "") {
return i;
}
}
return -1;}

void MisraGries(string element, vector <node> &memory) {
bool isHere = false;
int index;

for (int i = 0; i < memory.size(); i++) {
if (memory[i].id == element) {
isHere = true;
index = i;
}
}
if (isHere) {
memory[index].count++;
}
else {
int freeIndex = doWeHaveSpace(memory);
if (freeIndex+1) {
memory[freeIndex].count++;
memory[freeIndex].id = element;
}
else {
for (int i = 0; i < memory.size(); i++) {
if (memory[i].count != 0) {
memory[i].count--;
if (memory[i].count == 0) {
memory[i].id = "";
}
}
}
}
}
}
void filecheck(ifstream & input, string prompt)  // this function checks and opens input files
{
string filename;
cout << "Please enter file directory and name for " << prompt << ": ";
do
{
getline(cin, filename);
input.open(filename.c_str());
if (input.fail())
cout << " wrong file directory. Please enter real directory. ";
} while (input.fail());
}

int main() {
int line = 1;
string filename;
ifstream input;
ofstream output;
string search;
vector <node> frequent(1000);
for (int i = 0; i < frequent.size(); i++) {
frequent[i].id = "";
frequent[i].count = 0;
}
int k = 30;
string kMer;
filecheck(input, "input file");

while (!input.eof())
{
getline(input, search); // it gets infos line by line to count lines
line++;
if (line == 3) {
for (int i = 0; i < search.length() - k + 1; i++) {
kMer = search.substr(i, k);
MisraGries(kMer, frequent);
}
line = -1;
}

}

return 0;
}

2

Решение

Вы можете ускорить свой код, храня наиболее часто встречающиеся k-метры в хеш-таблице вместо массива. Таким образом, вы сможете обработать один k-мер в O(1) время (при условии, что длина постоянна), если он уже находится в кэше (если нет, то все равно потребуется линейный проход, но в среднем это может дать значительное улучшение).

Вы также можете сделать это еще быстрее, если есть много пропусков, храня дополнительную информацию в некоторой вспомогательной структуре данных (например, в очереди с приоритетами), чтобы вы могли найти элемент с count = 0 и удалите их, не проверяя все остальные элементы.

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

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

Подводя итог, я рекомендую увеличить кэш (если он умещается в памяти) и использовать более подходящую структуру данных, которая поддерживает быстрый поиск, например, хеш-таблицу (std::unordered_map в C ++).

1

Другие решения

Других решений пока нет …