【问题标题】:Using Map vs Vector in a class - speed在课堂上使用 Map vs Vector - 速度
【发布时间】:2013-12-01 18:52:15
【问题描述】:

您好,我编写了一个类的两个版本,一个使用地图,一个使用两个向量:

    class NucleotideSequence{
private:
    std::string Name;
    std::vector<int> BasePos;
    std::vector<char> BaseChar;
public:
    NucleotideSequence(std::string name, std::vector<int> &bp, std::vector<char> &bases);
    std::string getName();
    char getBase(int pos); // get a base by it's position in the char array.
    char getAbBase(int abPos); // get a base by it's actual bp position.
};


class NucleotideSequence2{
private:
    std::string Name;
    std::map<int, char> Sequence;
public:
    NucleotideSequence2(std::string &name, std::map<int, char> &seq) throw(FormatError);
    std::string getName();
};

然后我为它们定义了构造函数:

NucleotideSequence::NucleotideSequence(std::string name, std::vector<int> &bp, std::vector<char> &bases)
:Name(name), BasePos(bp), BaseChar(bases)
{
    for (std::vector<char>::iterator i = BaseChar.begin(); i != BaseChar.end(); i++) {
        switch (*i) {
            case 'A': case 'T': case 'C': case 'G': case '-': case 'N':
                break;
            case 'a':
                *i = 'A';
                break;
            case 't':
                *i = 'T';
                break;
            case 'c':
                *i = 'C';
                break;
            case 'g':
                *i = 'G';
                break;
            case 'n':
                *i = 'N';
                break;
            default:
                throw FormatError();
                break;
        }
    }
}

NucleotideSequence2::NucleotideSequence2(std::string &name, std::map<int, char> &seq) throw(FormatError)
: Name(name), Sequence(seq)
{
    for (std::map<int, char>::iterator i = Sequence.begin(); i != Sequence.end(); i++) {

        switch (i->second) {
            case 'A': case 'T': case 'C': case 'G': case '-': case 'N':
                break;
            case 'a':
                i->second = 'A';
                break;
            case 't':
                i->second = 'T';
                break;
            case 'c':
                i->second = 'C';
                break;
            case 'g':
                i->second = 'G';
                break;
            case 'n':
                i->second = 'N';
                break;
            default:
                throw FormatError();
                break;
        }
    }
}

这两个构造函数在两个不同的函数中调用:

NucleotideSequence Sequence_stream::get()
{
    if (FileStream.is_open() == false)
        throw StreamClosed(); // Make sure the stream is indeed open else throw an exception.
    if (FileStream.eof())
        throw FileEnd();
    char currentchar;
    int basepos = 0;
    std::string name;
    std::vector<char> sequence;
    std::vector<int> postn;
    currentchar = FileStream.get();
    if (FileStream.eof())
        throw FileEnd();
    if (currentchar != '>')
        throw FormatError();
    currentchar = FileStream.get();
    while(currentchar != '\n' && false == FileStream.eof())
    {
        name.append(1, currentchar);
        currentchar = FileStream.get();
    } // done getting names, now let's get the sequence.
    currentchar = FileStream.get();
    while(currentchar != '>' && false == FileStream.eof())
    {
        if(currentchar != '\n' && currentchar != ' '){
            basepos++;
            sequence.push_back(currentchar);
            postn.push_back(basepos);
        }
        currentchar = FileStream.get();
    }
    if(currentchar == '>')
    {
        FileStream.unget();
    }
    return NucleotideSequence(name, postn, sequence);
}


NucleotideSequence2 Sequence_stream::get2()
{
    if (FileStream.is_open() == false)
        throw StreamClosed(); // Make sure the stream is indeed open else throw an exception.
    if (FileStream.eof())
        throw FileEnd();
    char currentchar;
    int basepos = 0;
    std::string name;
    std::map<int, char> sequence;
    currentchar = FileStream.get();
    if (FileStream.eof())
        throw FileEnd();
    if (currentchar != '>')
        throw FormatError();
    currentchar = FileStream.get();
    while(currentchar != '\n' && false == FileStream.eof())
    {
        name.append(1, currentchar);
        currentchar = FileStream.get();
    } // done getting names, now let's get the sequence.
    currentchar = FileStream.get();
    while(currentchar != '>' && false == FileStream.eof())
    {
        if(currentchar != '\n' && currentchar != ' '){
            basepos++;
            sequence[basepos] = currentchar;
        }
        currentchar = FileStream.get();
    }
    if(currentchar == '>')
    {
        FileStream.unget();
    }
    return NucleotideSequence2(name, sequence);
}

然后可以从另一个函数调用这两个函数(它会捕获异常:以防您想知道未捕获的抛出)。

这两个类的区别是一个包含两个向量,而另一个类中包含相同的信息。

我的问题是:第一堂课和构建它的“get”非常快 - 几乎是即时的。 而构建第二个类(带有地图的那个)的“get2”- 明显较慢- 仅超过 5 秒。

为什么用映射构建类比用两个向量构建类慢 - 你应该看到我保持构造函数和两个 get 函数几乎相同,除了向向量添加元素或添加映射的键值对。所以我怀疑重复推回向量比重复添加键值对(即mymap['newkey'] = 'newvalue';)更快、更有效。

如何加快地图版本?

谢谢, 本。

【问题讨论】:

    标签: c++ class vector map


    【解决方案1】:

    向量执行一次分配(如果您提前告诉它所需的容量),或者最多执行少量次分配。地图为每个元素执行单独的动态分配

    您可能想尝试使用成对的排序向量,或者可能是“平面图”(在 Boost 中)或 btree-map(在 Google 代码中有一个)并比较性能。内存局部性可以产生巨大的影响,如果您不需要 std::map 的强大迭代器有效性保证,您可能会找到性能更好的数据结构。

    【讨论】:

    • 谢谢,我会尝试其中的一些——我的困境似乎是我有大型数据结构,所以说我想在我的班级中挑选一个元素——我猜有两个向量循环遍历第一个向量,直到我匹配我想要的值(相当于找到键),然后使用位置来获取第二个向量中的值。这里仅使用映射并为其提供键并立即获取值对于较大的结构来说更干净更好,但向量的构建速度更快 - 正如您所说的,因为分配。
    • 我们不要忘记boost::stable_vector,它将向量分配的效率与传统基于节点的容器(列表、集合、映射)的内存稳定性要求结合在一起。
    • 在这三个向量中,unordered_map,对向量——我实际上计时为最快的对向量——仅比两个向量略慢。如何使用其中一个值作为键有效地从一对向量中获取值?
    • @Ward9250:使用std::lower_bound,并保持向量排序(按第一个对元素的比较顺序)。
    • 我在构造函数中添加了一行以确保对向量进行排序:std::sort(Sequence.begin(), Sequence.end(), pairCompare); 其中定义了pairCompare:bool pairCompare(const std::pair&lt;int, char&gt;&amp; firstElem, const std::pair&lt;int, char&gt;&amp; secondElem) { return firstElem.first &lt; secondElem.first; }
    【解决方案2】:

    如何加快地图版本?

    尝试使用 unordered_map 代替常规地图。

    【讨论】:

      猜你喜欢
      • 2011-02-04
      • 2019-05-13
      • 2015-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多