如何改进链表搜索。 C ++

时间:2015-01-13 20:45:23

标签: c++ performance algorithm search linked-list

我在C ++中使用简单方法搜索链表中的字符串。这很好但我需要让它更快。可能吗?也许我需要按字母顺序将项目插入列表?但我不认为它可能会有助于列表清单。在列表中有大约30万个项目(单词)。

int GetItemPosition(const char* stringToFind)
{
    int i = 0;
    MyList* Tmp = FistListItem;
    while (Tmp){
        if (!strcmp(Tmp->Value, stringToFind))
        {
            return i;
        }
        Tmp = Tmp->NextItem;
        i++;
    }
    return -1;
}

如果找到项,则返回位置编号,否则返回-1。 任何sugesstion将是有帮助的。

感谢您的回答,我可以改变结构。我只有一个约束。代码必须实现以下接口:

int Count(void);
int AddItem(const char* StringValue, int WordOccurrence);
int GetItemPosition(const char* StringValue);
char* GetString(int Index);
int GetOccurrenceNum(int Index);
void SetInteger(int Index, int WordOccurrence);

那么您认为哪种结构最合适?

6 个答案:

答案 0 :(得分:5)

搜索链表是线性的,因此您需要逐个迭代,因此它是O(n)。链接列表不是最好的,如果你将它用于搜索,你可以使用更合适的数据结构,如二叉树。

订购元素没有多大帮助,因为仍然需要迭代每个元素。

Wikipedia article说:

  

在无序列表中,一个用于减少平均搜索时间的简单启发式算法是移动到前端的启发式算法,只需将元素移动到列表的开头即可。这个方案可以方便地创建简单的缓存,确保最近使用的项目也是最快查找的。      

另一种常见方法是使用more来“索引”链接列表   高效的外部数据结构。例如,一个人可以建立一个   红黑树或哈希表,其元素是引用的   链表节点。可以在单个上构建多个这样的索引   名单。缺点是可能需要更新这些索引   每次添加或删除节点时(或至少在该索引之前)   再次使用。)

因此,在第一种情况下,您可以通过移动先前更接近列表开头的项目来略微改善(通过统计假设)您的搜索性能。这假设将更频繁地搜索先前找到的元素。

第二种方法需要使用其他数据结构。

如果使用链表不是一项硬性要求,请考虑使用哈希表,排序数组(随机访问)或平衡树。

答案 1 :(得分:3)

考虑使用数组或std :: vector作为存储而不是链表,并使用二进制搜索来查找特定字符串,甚至更好的std :: set,如果您不需要数字索引。如果由于某些原因无法使用其他容器,则没有太多可能做的事情 - 您可能希望通过在节点中存储字符串的哈希值来加快比较过程。

答案 2 :(得分:1)

我建议哈希。 由于您已经拥有了自己的链接列表,因此您可以尝试使用链接列表进行链接以进行冲突解决。

答案 3 :(得分:1)

您可能希望使用二叉搜索树或红/黑树,而不是使用线性链接列表。这些树的设计旨在最大限度地减少遍历以查找项目。

您还可以存储“快捷链接”。例如,如果列表是字符串,则可以根据第一个字母开始搜索从哪里开始搜索的链接数组。

例如,shortcut['B']将返回指向第一个链接的指针,以开始搜索以“B”开头的字符串。

答案 4 :(得分:0)

答案是不,您无法在不更改数据结构的情况下改进搜索

按照目前的情况,对列表进行排序不会让您更快地搜索任何随机项目。

它只允许您通过针对第一项(将是最小或最大的条目)进行测试来快速确定给定项目是否在列表中,并且这种改进不太可能产生很大的不同。 / p>

那么请你编辑你的问题并向我们解释你的约束

  • 您可以使用完全不同的数据结构,例如数组或树吗? (正如其他人所建议的那样)
  • 如果没有,您可以修改链接列表的链接方式吗?
  • 如果没有,我们将不太可能帮助你...

答案 5 :(得分:0)

最好的选择是使用更快的数据结构来存储字符串:

  • std :: map - 幕后的红黑树。具有搜索/插入/删除操作的O(logn)。适用于您希望使用字符串存储其他值(例如 - 位置)。
  • std :: set - 基本上是相同的树,但没有值。最适用于只需要包含操作的情况。
  • std :: unordered_map - 哈希表。 O(1)访问。
  • std :: unordered_set - 哈希集。也是O(1)访问。

注意。但在所有这些情况下都有一个问题。复杂性仅基于n(字符串数)计算。实际上,字符串比较不是免费的。因此,O(1)变为O(m),O(logn)变为O(mlogn)(其中m是字符串的最大长度)。在相对短的字符串的情况下这无关紧要。但如果不是这样,请考虑使用Trie。在实践中,trie甚至可以比哈希表更快 - 查询字符串的每个字符只被访问一次而不是多次。对于哈希表/设置它至少一次用于哈希计算,并且至少一次用于实际字符串比较(取决于冲突解决策略 - 不确定它是如何在C ++中实现的)。