如何CPU有效地将项目添加到唯一项目列表

时间:2015-11-26 18:45:26

标签: algorithm performance

序言:这个问题应该是语言中立的,这是关于算法的学术问题,但为了清楚起见,因为它是我最喜欢的语言,我将用C ++编写例子。

想象一下简单的结构:

struct Item
{
    char Char;
    std::string String;
};

现在,我有一个这些项目的列表,比如std::vector<Item> list。我想要的是创建一个函数,允许我将项添加到此列表,但如果项已经在列表中,则跳过。因此它只包含每个项目一次。我想到的最简单的实现是:

void AppendItem(Item item)
{
    // Check if the item is in the list and if yes, exit the function
    foreach (Item x, list)
    {
        // Compare char first, because comparing 2 chars is as CPU complex as comparing 2 numbers
        if (item.Char != x.Char)
            continue;
        // Now we can compare the strings, which is relatively complex operation
        if (item.String == x.String)
            return;
    }
    // There clearly isn't any such item in a list, so let's add it
    list.push_back(item);
}

到目前为止,它看起来像一个愚蠢的问题,它实际上是。但现在它变得更有趣了。

想象一下,列表中已有2000个项目,我想再添加1000个项目。我不知道这些1000中是否有任何已列入清单。

如果我递归地使用这个哑函数,我会导致每个项目循环2000 + N次(N为0 - 999)* 1000.考虑到字符串比较的实现,这是非常慢的。即使在我的i7 CPU上它也很慢。

有没有更智能的算法如何实现这一目标?我甚至可以牺牲一些RAM,只要它会少吃CPU。

2 个答案:

答案 0 :(得分:3)

几乎每种语言都有一个优化列表,仅用于保存唯一值。在C ++中,您可以使用std::set而不是列表。在C#中,您将使用HashSet。在JavaScript中,您将使用对象...

在您的问题中,您正在为每个元素执行O(N)查找,一个集合或唯一列表将至少执行O(log(N)),这会快很多倍。

答案 1 :(得分:-1)

因此,您确定要添加的1000个项目彼此之间是唯一的吗?

如果是这样,那么一种可能性是首先检查是否要添加一个项目(不在列表中),然后将它们临时保存在单独的列表中。然后你连接两个列表。

另一个优化方法是根据项目的字符串数据成员按字母顺序保持列表的排序顺序。这样,您可以使用二进制搜索算法等搜索方法来加快检查唯一性的过程。