哪种数据结构和算法适用于此?

时间:2013-12-25 06:08:05

标签: c++ string algorithm stl

我有1000个字符串。给定需要在所有字符串中搜索的模式,并返回包含该模式的所有字符串。

目前我使用vector来存储原始字符串。搜索模式,如果匹配,则将其添加到新向量中,最后返回向量。

int main() {
    vector <string> v;
    v.push_back ("maggi");
    v.push_back ("Active Baby Pants Large 9-14 Kg ");
    v.push_back ("Premium Kachi Ghani Pure Mustard Oil ");
    v.push_back ("maggi soup");
    v.push_back ("maggi sauce");
    v.push_back ("Superlite Advanced Jar");
    v.push_back ("Superlite Advanced");
    v.push_back ("Goldlite Advanced"); 
    v.push_back ("Active Losorb Oil Jar"); 

    vector <string> result;

    string str = "Advanced";

    for (unsigned i=0; i<v.size(); ++i)
    {
        size_t found = v[i].find(str);
        if (found!=string::npos)
            result.push_back(v[i]);
    }

    for (unsigned j=0; j<result.size(); ++j)
    {
        cout << result[j] << endl;
    }
    // your code goes here
    return 0;

}

是否有任何最佳方法可以实现相同的复杂性和更高的性能?

4 个答案:

答案 0 :(得分:2)

我认为容器适合您的应用。

然而,如果您实现自己的std::string::find而不是KMP algorithm,那么您可以保证时间复杂度在字符串+搜索字符串的长度方面是线性的。
http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

因此std::string::find的复杂性未具体说明 http://www.cplusplus.com/reference/string/string/find/

编辑:正如此链接所指出的,如果字符串的长度不大(超过1000),那么可能使用std::string::find就足够了,因为这里不需要制表等。
C++ string::find complexity

答案 1 :(得分:0)

如果结果与输入字符串向量在同一代码块中使用(在您的示例中是这样),或者即使您保证每个人仅在输入存在时使用结果,您实际上不需要复制字符串。这可能是一项昂贵的操作,这会大大降低总算法的速度。

相反,您可以使用指针向量作为结果:

vector <string*> result;

答案 2 :(得分:0)

如果许多搜索的字符串列表是“固定的”,那么你可以做一些简单的预处理,通过使用倒排索引来大大加快速度。

构建字符串中存在的所有字符的映射,换句话说,为每个可能的char存储建立包含该字符串的所有字符串的列表:

std::map< char, std::vector<int> > index;
std::vector<std::string> strings;

void add_string(const std::string& s) {
    int new_pos = strings.size();
    strings.push_back(s);
    for (int i=0,n=s.size(); i<n; i++) {
        index[s[i]].push_back(new_pos);
    }
}

然后当被要求搜索子字符串时,首先检查反向索引中的所有字符,并仅在具有最少条目数的索引中的列表上进行迭代:

std::vector<std::string *> matching(const std::string& text) {
    std::vector<int> *best_ix = NULL;
    for (int i=0,n=text.size(); i<n; i++) {
        std::vector<int> *ix = &index[text[i]];
        if (best_ix == NULL || best_ix->size() > ix->size()) {
            best_ix = ix;
        }
    }

    std::vector<std::string *> result;
    if (best_ix) {
        for (int i=0,n=best_ix->size(); i<n; i++) {
            std::string& cand = strings[(*best_ix)[i]];
            if (cand.find(text) != std::string::npos) {
                result.push_back(&cand);
            }
        }
    } else {
        // Empty text as input, just return the whole list
        for (int i=0,n=strings.size(); i<n; i++) {
            result.push_back(&strings[i]);
        }
    }
    return result;
}

可能有许多改进:

  • 使用更大的索引(例如,使用成对的连续字符)
  • 避免考虑非常常见的字符(停止列表)
  • 使用从三元组或更长序列计算的哈希值
  • 搜索十字路口,而不是搜索较短的列表。给定元素的添加顺序无论如何已经对矢量进行了排序,甚至可以使用向量来有效地计算交集(参见std::set_intersection)。

根据问题的参数(有多少字符串,多长时间,被搜索的文本多长时间......),所有这些都可能有意义或无意义。

答案 3 :(得分:0)

如果源文本较大且是静态的(例如已抓取的网页),则可以通过预先构建suffix treetrie数据结构来节省搜索时间。搜索模式可以遍历树以查找匹配项。

如果源文本很小且经常更改,那么您的原始方法是合适的。 STL功能通常非常优化,经得起时间的考验。