在我的实验性编程语言的解释器中,我有一个符号表。每个符号由一个名称和一个值组成(值可以是例如:string,int,function等类型。)
首先,我用一个向量表示该表,并通过符号迭代检查给定的符号名称是否合适。
然后我使用地图(在我的情况下为map<string,symbol>
)比在但 >完整地迭代矢量更好:
解释这部分有点难,但我会尝试。
如果在我的语言的程序中第一次检索变量,当然必须找到它在符号表中的位置(现在使用vector)。如果我每次执行该行时都会迭代向量(想到一个循环),那么它将非常慢(因为它目前是,几乎和microsoft的批处理一样慢)。
所以我可以使用地图来检索变量:SymbolTable[ myVar.Name ]
但请注意以下几点:如果第一次找到仍使用向量的变量,我可以将它的精确整数位置存储在向量中。这意味着:下次需要时,我的翻译人员知道它已被“缓存”并且不会在符号表中搜索它,而是执行SymbolTable.at( myVar.CachedPosition )
之类的操作。
现在我的(相当难的?)问题:
我是否应该使用矢量作为符号表并缓存矢量中变量的位置?
我应该使用地图吗?为什么? []运算符的速度有多快?
我应该使用完全不同的东西吗?
答案 0 :(得分:17)
地图是用于符号表的好东西。但地图的operator[]
不是。通常,除非您编写一些简单的代码,否则应使用地图的成员函数insert()
和find()
而不是operator[]
。 operator[]
的语义有点复杂,如果您要查找的符号不在地图中,几乎肯定不会做您想要的。
至于map
和unordered_map
之间的选择,在实施简单的解释性语言时,性能的差异极不可能显着。如果使用map,则保证所有当前的标准C ++实现都支持它。
答案 1 :(得分:13)
你实际上有很多选择。
存在库:
vector
对实现的地图界面,由于缓存位置的原因,比小型或冻结集的地图更快。<强>评论家强>
O(log N)
映射查找和检索,但这些项目可能分散在整个内存中,因此无法很好地使用缓存策略。O(N)
上的find
性能会被接受,是否可以接受?unordered_map
?它们提供O(1)
查找和检索(尽管常量可能很高)并且当然适合于此任务。如果您查看维基百科关于Hash Tables的文章,您会发现有很多可用的策略,您当然可以选择一个适合您特定使用模式的策略。答案 2 :(得分:4)
通常情况下,您会使用符号表来查找源名称中显示的名称变量。在这种情况下,您只能使用名称,因此无法在变量符号表中存储变量的缓存位置。所以我会说map
是一个不错的选择。 []
运算符需要的时间与映射中元素数量的对数成比例 - 如果结果很慢,则可以使用像std::tr1::unordered_map
这样的哈希映射。
答案 3 :(得分:2)
std :: map的operator []占用O(log(n))时间。这意味着它非常有效,但您仍然应该避免一遍又一遍地进行查找。您可以存储对该值的引用,还是存储容器的迭代器,而不是存储索引?这避免了必须完全进行查找。
答案 4 :(得分:2)
当大多数解释器解释代码时,他们首先将其编译成中间语言。这些中间语言通常通过索引或指针引用变量,而不是名称。
例如,Python(C实现)通过索引将局部变量更改为引用,但全局变量和类变量使用哈希表通过名称引用。
我建议查看关于编译器的介绍性文本。
答案 5 :(得分:1)
a std::map
(O(log(n)))或散列表(“摊销”O(1))将是第一选择 - 如果确定它是瓶颈,则使用自定义机制。通常,使用散列或标记输入是第一个优化。
在对其进行分析之前,最重要的是隔离查找,以便您可以轻松地替换和分析它。
std::map
对于少数元素来说可能稍微慢一点(但是,它并不重要)。
答案 6 :(得分:0)
Map是O(log N),因此不如数组中的位置查找快。但确切的结果将取决于很多因素,因此最好的方法是以允许您稍后在实现之间交换的方式与容器交互。也就是说,编写一个“查找”函数,可以通过任何合适的容器有效地实现,以允许自己切换和比较不同实现的速度。
答案 7 :(得分:0)
Map的operator []是O(log(n)),参见维基百科:http://en.wikipedia.org/wiki/Map_(C%2B%2B)
我认为,当你经常寻找符号时,使用地图肯定是正确的。也许哈希地图(std::unordered_map)可以使您的表现更好。
答案 8 :(得分:0)
如果您要使用vector
并且遇到缓存最新符号查找结果的麻烦,如果您的符号表可以执行相同的操作(缓存最新的查找结果)实现为map
(但在使用map
的情况下,缓存可能不会有很多好处)。使用map
,您可以获得额外的优势,即任何非缓存符号查找都比在vector
中搜索更高效(假设vector
未排序 - 如果你不得不多次进行排序,保持矢量排序可能会很昂贵。
拿Neil's advice; map
通常是符号表的良好数据结构,但您需要确保正确使用它(而不是意外添加符号)。
答案 9 :(得分:0)
你说:“如果第一次找到仍然使用向量的变量,我可以用它存储它在矢量中的确切整数位置。”。
您可以对地图执行相同操作:使用find
搜索变量并存储指向它的iterator
而不是位置。
答案 10 :(得分:0)
为了查找值,通过字符串键,地图数据类型是合适的,如其他用户所述。
STL地图实现通常使用self-balancing trees实现,就像red black tree数据结构一样,并且它们的操作需要O(logn)时间。
我的建议是将表操作代码包装在函数中,
例如table_has(name)
,table_put(name)
和table_get(name)
。
通过这种方式,您可以轻松更改内部符号表表示 运行时间性能较慢,此外您可以在以后嵌入这些例程缓存功能。
答案 11 :(得分:0)
地图将扩展得更好,这将是一个重要的功能。但是,不要忘记在使用地图时,您可以(与矢量不同)获取指针和引用。在这种情况下,您可以使用地图轻松地“缓存”变量,就像向量一样有效。地图几乎肯定是这里的正确选择。