gpt4 book ai didi

algorithm - 可翻转数据结构的模式名称?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:05:57 26 4
gpt4 key购买 nike

我在想一个命名约定,它准确地表达了我正在设计的类中发生的事情。其次,我试图在两个几乎相等的用户api之间做出选择。
情况是这样的:
我正在构建一个科学应用程序,其中一个中心数据结构有三个阶段:1)积累,2)分析,3)查询执行。
在我的例子中,它是一个空间建模结构,在内部使用KDTree来划分三维空间中的点集合每个点描述了周围环境的一个或多个属性,对测量本身具有一定程度的信心。
在向集合中添加(可能大量)度量之后,对象的所有者将查询该集合,以在适用字段中的某个新数据点处获取插值度量。
这个api看起来像这样(代码是用java编写的,但这并不重要;为了清楚起见,代码分为三个部分):

// SECTION 1:
// Create the aggregation object, and get the zillion objects to insert...
ContinuousScalarField field = new ContinuousScalarField();
Collection<Measurement> measurements = getMeasurementsFromSomewhere();

// SECTION 2:
// Add all of the zillion objects to the aggregation object...
// Each measurement contains its xyz location, the quantity being measured,
// and a numeric value for the measurement. For example, something like
// "68 degrees F, plus or minus 0.5, at point 1.23, 2.34, 3.45"
foreach (Measurement m : measurements) {
field.add(m);
}

// SECTION 3:
// Now the user wants to ask the model questions about the interpolated
// state of the model. For example, "what's the interpolated temperature
// at point (3, 4, 5)
Point3d p = new Point3d(3, 4, 5);
Measurement result = field.interpolateAt(p);

对于我的特定问题域,在第2节中可以执行少量的增量工作(将这些点划分为一个平衡的kdtree)。
在第3节中会有少量的工作(执行一些线性插值)。
但是在第2节和第3节之间必须进行大量的工作(构造一个核密度估计器并执行一个快速高斯变换,使用泰勒级数和hermite函数,但这完全不重要)。
有时在过去,我只是使用惰性求值来构造数据结构(在本例中,是在第一次调用“interpolateAt”方法时),但是如果用户再次调用“field.add()”方法,我就必须完全放弃这些数据结构,从头开始。
在其他项目中,我要求用户显式调用“object.flip()”方法,从“append mode”切换到“query mode”。这种设计的好处在于,用户可以更好地控制核心计算开始的确切时刻。但对于api使用者来说,跟踪对象的当前模式可能是一个麻烦。此外,在标准用例中,调用者在开始发出查询后从不向集合中添加另一个值;数据聚合几乎总是完全早于查询准备。
你们是如何设计这样的数据结构的?
您是否更喜欢让对象懒洋洋地执行其繁重的分析,在新数据进入集合时丢弃中间数据结构?或者您是否要求程序员显式地将数据结构从追加模式翻转到查询模式?
你知道这样的对象有什么命名约定吗有没有一个我没想到的模式?
编辑时:
对于我在示例中使用的名为“continuousScalarField”的类,似乎有些困惑和好奇。
通过阅读这些维基百科页面,你可以对我所说的有一个很好的了解:
http://en.wikipedia.org/wiki/Scalar_field
http://en.wikipedia.org/wiki/Vector_field
假设您想要创建一个地形图(这不是我的确切问题,但在概念上非常相似)所以你在一平方英里的范围内进行一千次高度测量,但是你的测量设备在高度上有正负10米的误差。
一旦你收集了所有的数据点,你就可以把它们输入到一个模型中,这个模型不仅可以插值,还可以考虑每个测量的误差。
要绘制地形图,请查询模型中要绘制像素的每个点的高程。
至于一个类是否应该同时负责追加和处理查询的问题,我不是百分之百确定,但我认为是这样。
下面是一个类似的例子:hashmap和treemap类允许添加和查询对象。添加和查询没有单独的接口。
这两个类也与我的示例相似,因为必须持续维护内部数据结构以支持查询机制。hashmap类必须周期性地分配新内存,重新散列所有对象,并将对象从旧内存移动到新内存。树映射必须使用红黑树数据结构来持续保持树的平衡。
唯一的区别是,如果我的类在知道数据集已关闭后能够执行其所有计算,那么它将以最佳方式执行。

最佳答案

我通常更喜欢有一个明确的改变,而不是懒洋洋地重新计算结果这种方法使实用程序的性能更加可预测,并且它减少了为提供良好的用户体验而必须做的工作。例如,如果这发生在用户界面中,我在哪里需要担心弹出沙漏等?哪些操作将在可变时间内阻塞,并且需要在后台线程中执行?
也就是说,与其显式地更改一个实例的状态,我建议使用Builder Pattern来生成一个新对象。例如,您可能有一个aggregator对象,它在添加每个示例时执行少量工作然后,我将有一个void flip()方法,它获取当前聚合的副本并执行所有繁重的数学运算,而不是您建议的Interpolator interpolator()方法。interpolateAt方法将位于这个新的插值器对象上。
如果您的使用模式需要,您可以通过保留对所创建的内插器的引用来执行简单的缓存,并将其返回给多个调用方,只有在修改聚合器时才将其清除。
这种职责分离有助于产生更易于维护和重用的面向对象程序。一个可以在请求的Measurement处返回Point的对象是非常抽象的,也许许多客户机可以将您的插值器用作实现更通用接口的一种策略。
我认为你所加的比喻是误导性的。考虑另一种类比:

Key[] data = new Key[...];
data[idx++] = new Key(...); /* Fast! */
...
Arrays.sort(data); /* Slow! */
...
boolean contains = Arrays.binarySearch(data, datum) >= 0; /* Fast! */

这可以像集合一样工作,实际上,它比 Set实现(使用哈希表或平衡树实现)提供更好的性能。
平衡树可以看作是插入排序的有效实现。每次插入后,树都处于排序状态。平衡树的可预测时间要求是由于排序的成本分散在每个插入上,而不是发生在某些查询而不是其他查询上。
哈希表的重新灰化确实会导致性能不太一致,因此不适合某些应用程序(可能是实时微控制器)。但即使是重新灰化操作也只取决于表的负载因子,而不是插入和查询操作的模式。
为了让你的类比严格成立,你必须对你添加的每一个点“排序”(做毛茸茸的数学运算)但这听起来可能会导致成本高昂,从而导致构建器或工厂方法模式。当客户需要为冗长的“排序”操作做好准备时,这就向他们表明了这一点。

关于algorithm - 可翻转数据结构的模式名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/247857/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com