【问题标题】:most efficient way to compare short string with small dictionary (parsing)将短字符串与小字典(解析)进行比较的最有效方法
【发布时间】:2012-07-09 17:13:20
【问题描述】:

我正在尝试优化我只是为了好玩而制作的简单 C 解释器,我正在做这样的解析 - 首先我将文件解析为双向链表中的标记,然后我进行语法和语义分析。
我想用这个原型优化功能:

bool parsed_keyword(struct token *, char dictionary[][]);

在函数内部,我基本上针对 所有关键字 调用 strcmp 并编辑令牌类型。 这当然会导致(几乎)每个正在解析的字符串调用 20 次 strcmp。

我认为 Rabin-Karp 会是最好的,但在我看来它并不最适合这项工作(将一个单词与小字​​典匹配)。 完成这项工作的最佳算法是什么?感谢您的任何建议。

【问题讨论】:

  • 谈到n = 20 优化应该是您最不关心的问题。几乎任何阶多项式函数都可以满足您的需求。
  • 根据 Niklaus Wirth 的说法,当您在编译器/解释器中查找本地符号时,最有效的处理方式。他甚至做了测试以确保。 (当然,他的指标可能与你的不同,但他的指标非常好。)

标签: c algorithm parsing lexical-analysis


【解决方案1】:

哈希表可能是我解决这个特定问题的选择。它将为您的大小的表提供O(1) 查找。不过,trie 也是一个不错的选择。

但是,最简单的实现方法是将您的单词按字母顺序放在一个数组中,然后使用 C 库中的 bsearch。它应该几乎与哈希或特里一样快,因为您只处理 30 个单词。它实际上可能比哈希表更快,因为您不必计算哈希值。

Steve Jessop 的想法是一个不错的想法,将您的字符串首尾相连地布置在大小相同的 char 数组中。

const char keywords[][MAX_KEYWORD_LEN+1] = {
 "auto", "break", "case", /* ... */, "while"
};

#define NUM_KEYWORDS sizeof(keywords)/sizeof(keywords[0])

int keyword_cmp (const void *a, const void *b) {
    return strcmp(a, b);
}

const char *kw = bsearch(word, keywords, NUM_KEYWORDS, sizeof(keywords[0]),
                         keyword_cmp);

int kw_index = (kw ? (const char (*)[MAX_KEYWORD_LEN+1])kw - keywords : -1);

如果您还没有,您应该考虑购买一份Compilers: Principles, Techniques, and Tools。由于它的封面,它通常被称为龙之书

【讨论】:

  • 如果你用 nul 字节填充所有单词到最长的长度,那么二分查找就变得特别简单,因为你可以将字符串首尾相连——没有第二次间接。由于它们是关键字,因此列表不会经常更改。
  • @SteveJessop:我在答案中添加了您的实施建议,问候
  • 不相关,但在所有可笑的 comp sci 书籍(恐龙 os 书籍;更不用说所有 o'reilly 的动物书籍)的封面中,编译器书籍拥有最酷的封面。
  • @publ1c_stat1c:感谢您提醒我有关封面的事情,我更新了答案。问候
  • 不错的答案,还没有真正想到这个技巧。谢谢。
【解决方案2】:

如果您正在寻找效率,我会说 Rabin Karp 不是您的最佳选择,而 Boyer-Moore 会发现您的最佳效率,尽管实施起来要困难一些。

如果您这样做是为了好玩,老实说,我认为没有任何优化的必要,因为这些调用仍应在很短的时间内运行,而且您并不真的需要它以行业速度运行。

如果您正在尝试使用字符串匹配算法,这是一个很酷且有用的目标,我建议您研究一下 KMP 算法和 Boyer-Moore 算法,这两种算法都会在实施过程中教给您很多东西。

当然还有其他更直接的方法,例如字典查找和简单的二进制搜索等...,但这些方法并没有真正优化您正在处理字符串的事实,而且字符串比较是一个非常有趣的领域,您在某些时候不可避免地会遇到。

【讨论】:

  • 不,boyer moore 在这种特定情况下非常无效(匹配多个单词),可能与天真的匹配算法一样低效。是的,我这样做只是为了好玩,否则我可能根本不在乎。
【解决方案3】:

假设您的关键字没有改变,这听起来像是perfect hash function 的正确案例。完美的散列函数将输入映射到整数(如常规散列函数),但不会发生冲突。

Wikipedia 有几个完美的哈希生成器的链接,包括GNU gperf

【讨论】:

    【解决方案4】:

    在进行查找时首先想到的就是使用键盘的排序数组,然后对它们进行二分搜索。

    【讨论】:

      【解决方案5】:

      如果关键字集是固定的,您可以使用完美哈希,例如使用gperf。这只需要持续的工作和单个字符串比较,因此可能比其他方法更快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-10-05
        • 2013-07-28
        • 2017-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多