我打算创建一个表示严格的部分有序集的类,我假设对其接口进行建模的最自然方式是二元关系。这给出了以下功能:
bool test(elementA, elementB); //return true if elementA < elementB
void set(elementA, elementB); //declare that elementA < elementB
void clear(elementA, elementB); //forget that elementA < elementB
可能的功能如下:
void applyTransitivity(); //if test(a,b) and test(b, c), then set(a, c)
bool checkIrreflexivity(); //return true if for no a, a < a
bool checkAsymmetry(); //return true if for no a and b, a < b and b < a
天真的实现将是具有对的列表,使得(a,b)指示&lt;湾但是,它可能不是最佳的。例如,test
将是线性时间。也许最好将其作为列表的哈希映射。
理想情况下,内存表示本质上强制applyTransitivity
始终是&#34;实际上&#34;并且不允许产生导致反射性或对称性的边缘。换句话说,数据结构的自由度代表严格的poset的自由度。有没有一种已知的方法来做到这一点?或者,更现实地说,有一种方法可以检查是否具有周期性,并保持每次调用set
和clear
时的摊销和迭代的传递性,从而降低执行正确性的成本。是否有可行的实施?
答案 0 :(得分:1)
好的,让我们谈谈实现裸金属刮削微效率,你可以选择深入了解你想要去的深渊。在这种架构层面,没有像哈希映射和列表这样的数据结构,甚至没有数据类型,只有内存中的位和字节。
除此之外,您还可以通过查看DAG的常见表示来查找有关表示的大量信息。但是,大多数常见代表的设计更多是为了方便而不是效率。
在这里,我们希望将a
的数据与该邻接数据融合到一个内存块中。因此,您希望存储与a
自己的内存块中a's
有关系的项目,以便我们可以访问{{1}和单个缓存行中与a
相关的所有元素(如果这些相关元素也可能适用于同一缓存行,那么奖励积分,但这是一个NP难问题)。
您可以通过在a
中存储32位索引来实现。如果我们更高一级并且使用C作为示例性目的,我们可以像这样建模这样的对象:
a
这使得struct Node
{
// node data
...
int links[]; // variable-length struct
};
是一个可变长度的结构,其大小甚至地址都会发生变化,所以我们需要一个额外的间接级别来获得稳定性并避免失效,就像索引的索引一样(如果你控制了内存分配器/数组,它纯粹是连续的),或指针的索引(或某些语言中的引用)。
这使得您的测试函数仍然涉及线性时间搜索,但相对于与Node
相关的元素数量而言是线性的,而不是元素总数。因为我们使用了可变长度结构,a
及其邻居索引可能适合单个缓存行,并且a
可能已经在缓存中只是为了使查询。
它类似于存储列表的哈希映射的基本思想,但没有列表开销的爆炸和没有哈希查找(可能是恒定时间但不像访问连接那么快)来自同一内存块的a
。最重要的是,它对缓存更友好,并且通常会在几个周期和数百个周期之间产生差异。
现在这意味着你仍然需要卷起袖子并检查自己的周期。如果您想要一个更直接,更方便地对问题进行建模的数据结构,那么您将发现一个更好的图形数据结构,围绕有向边缘的形式化。但是,这些比它们更有效率更方便。
如果你需要容器是通用的,a
可以是任何给定的类型,那么你总是可以包装它(现在使用C ++):
a
并且仍然将这一切融合到一个内存块中。我们需要在这里放置new来保存那些C ++对象语义,并且可能会在这里注意对齐。
传递性检查总是涉及某种搜索(广度优先或深度优先)。我不认为除非你想记住/缓存潜在的大量传递数据,否则任何代表都会避免这种情况。
在这一点上,如果你想深入了解深渊并找到一个难以维持和理解的解决方案,你应该有一些非常快的东西。不幸的是,我发现这并没有给女士们留下太深刻的印象,就像拥有一辆非常快的汽车一样,但它可以使你的软件变得非常非常快。