I.刚刚实现了一种按位trie(基于nedtries),但我的代码做了很多
内存分配(对于每个节点)。
与我的实施相反,在其他事物中,nedtries声称速度很快,
因为它们的内存分配数量很少(如果有的话)。
作者声称他的实施是“就地”的,但在这种情况下它的真正含义是什么?
nedtries如何实现如此少量的动态内存分配?
Ps:我知道这些来源是可用的,但代码很难遵循,我无法弄清楚它是如何工作的
答案 0 :(得分:10)
我是作者,所以这是为了谷歌的许多人的利益,他们同样在使用nedtries方面遇到困难。我要感谢这里的人们在stackflow上没有对我个人做出令人不快的评论,其他一些关于nedtries的讨论也是如此。
typedef struct foo_s foo_t;
struct foo_s {
NEDTRIE_ENTRY(foo_t) link;
size_t key;
};
typedef struct foo_tree_s foo_tree_t;
NEDTRIE_HEAD(foo_tree_s, foo_t);
static foo_tree_t footree;
static size_t fookeyfunct(const foo_t *RESTRICT r)
{
return r->key;
}
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s));
int main(void)
{
foo_t a, b, c, *r;
NEDTRIE_INIT(&footree);
a.key=2;
NEDTRIE_INSERT(foo_tree_s, &footree, &a);
b.key=6;
NEDTRIE_INSERT(foo_tree_s, &footree, &b);
r=NEDTRIE_FIND(foo_tree_s, &footree, &b);
assert(r==&b);
c.key=5;
r=NEDTRIE_NFIND(foo_tree_s, &footree, &c);
assert(r==&b); /* NFIND finds next largest. Invert the key function to invert this */
NEDTRIE_REMOVE(foo_tree_s, &footree, &a);
NEDTRIE_FOREACH(r, foo_tree_s, &footree)
{
printf("%p, %u\n", r, r->key);
}
NEDTRIE_PREV(foo_tree_s, &footree, &a);
return 0;
}
你声明你的项目类型 - 这里是struct foo_s。你需要内部的NEDTRIE_ENTRY(),否则它可以包含你喜欢的任何东西。您还需要一个密钥生成功能。除此之外,它是漂亮的样板。
我自己也不会选择这种基于宏的初始化系统!但它是为了与BSD rbtree.h兼容,所以使用BSD rbtree.h很容易交换到任何东西。
关于我对“就地”的使用 算法,我想我的缺乏 计算机科学培训表明 这里。我称之为“到位” 是你只使用记忆的时候 传入一段代码,如果 你把64个字节移到了原地 算法它只会触及64 字节即它不会使用 额外的元数据,或分配一些 额外的记忆,或者确实写到 全球国家。一个很好的例子是 “就地”排序实施在哪里 只有正在排序的集合 (我想是线程堆栈) 感动了。
因此没有,nedtries不需要 内存分配器。它存储了所有 它在NEDTRIE_ENTRY中需要的数据 和NEDTRIE_HEAD宏扩展。 换句话说,当你分配 你的struct foo_s,你做的都是 nedtries的内存分配。
关于理解“宏观 善良“,它更容易 如果编译就能理解逻辑 它作为C ++然后调试它:)。该 C ++ build使用模板和 调试器会干净地显示状态 在任何给定的时间。事实上,所有 我的调试发生在一个 C ++构建和我一丝不苟 将C ++更改转录为 macroised C。
最后,在新发布之前,我 搜索谷歌的人 我的软件问题,看看是否 我可以解决问题而且通常都是 惊讶于别人的评价 我和我的免费软件。首先, 为什么没有那些人 困难直接问我 救命?如果我知道有 那么,文档出了问题 我可以解决它们 - 同样,请问 stackoverflow不让我知道 马上就有了一个文档 问题bur相当依赖我 找到下一个版本。所以我会 说是如果有人发现了 我的文档有问题,请做 给我发电子邮件并说出来,即使在那里 是一个像这里一样的讨论 stackflow。
尼尔
答案 1 :(得分:4)
就地表示您对原始(输入)数据进行操作,因此输入数据成为输出数据。 非就地表示您具有单独的输入和输出数据,并且不会修改输入数据。 就地操作具有许多优点 - 较小的缓存/内存占用,较低的内存带宽,因此通常具有更好的性能等,但它们具有破坏性的缺点,即您丢失了原始输入数据(可能或可能不重要,取决于用例)。
答案 2 :(得分:4)
我看了一下nedtrie.h源代码。 它似乎是“就地”的原因是你必须将trie簿记数据添加到您要存储的项目中。
您使用NEDTRIE_ENTRY宏将父/子/下一个/上一个链接添加到您的数据结构,然后您可以将该数据结构传递给各种trie例程,这些例程将提取并使用这些添加的成员。
所以它是“就地”的,因为你增加了现有的数据结构和trie代码搭载它。
至少这就是它的样子。该代码中有很多宏观优点,所以我可能会让自己感到困惑(:
答案 3 :(得分:-1)
就地意味着对输入数据进行操作并(可能)更新它。这意味着没有复制和/或移动输入数据。这可能会导致丢失输入数据原始值,如果它与您的特定情况相关,则需要考虑这些值。