找到最常见的k-mers及其在C ++中的出现次数

时间:2017-04-19 20:33:39

标签: c++ algorithm memory bioinformatics

关于kmer https://en.wikipedia.org/wiki/K-mer

我试图在一个大的fastq文件中找到最常见的k-mers。我的计划是使用misra-gries算法找到最常见的k-mers,然后用第二遍搜索文件中的每个频繁k-mer的计数。但我认为我的算法不够高效。这是我的下面的第一稿。我尽量保持内存效率。(程序不能耗尽内存)

我也发现了这个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;
}

1 个答案:

答案 0 :(得分:1)

您可以通过将最常用的k-mers存储在哈希表而不是数组中来加速代码。通过这种方式,您可以在O(1)时间内处理一个k-mer(假设长度是常数),如果它已经在缓存中(如果它不在,它仍然需要线性传球,但平均可能会有很大的提升。

如果通过在某种辅助数据结构(如优先级队列)中保留其他信息而导致很多未命中,您也可以使其更快,以便您可以找到count = 0的元素并删除它们而不检查所有其他元素。

考虑到k在您的示例中非常小,您可以增加内存缓存的大小(典型的计算机应该很容易在内存中保留数百万个这样的字符串),以便&# 39;重新减少错过。

您可以在第一次传递期间通过哈希k-mers存储更多数据(这样,您只需要将整数存储在内存而不是字符串中)。

总结一下,我建议将缓存设置得更大(只要它适合内存)并使用更合适的数据结构来支持快速查找,例如哈希表(std::unordered_map在C ++)。