高级:如何优化我的复数O(n²)算法

本文关键字:算法 #178 我的 何优化 高级 优化 | 更新日期: 2023-09-27 18:09:11

我有人物和地点数据:

  • Person实体有
    • IList<DateRangePlaces>各有
      • IList<Place>的可能位置
    • Schedule日模式为ie。10天可用4天不可用

在特定的DateRangePlaces日期范围内,人们必须服从Schedule模式,无论人们是否可以去特定的地方。

  • Place实体有
    • IList<DateRangeTiming>每个定义每个日期范围内的开放/关闭时间

重叠的日期范围作为后进先出工作。因此,对于之前已经定义的每一天,新的时间定义优先。

现在我需要这样做(在伪代码中):

for each Place
{
    for each Day between minimum and maximum date in IList<DateRangeTiming>
    {
        get a set of People applicable for Place and on Day
    }
}

这意味着执行我的任务的步骤数大约是:

总和;<子>(地方)(总和;<子>(天)×总和;<子>(人)

我的理解是

0 (x × yx x z)

<罢工>可能近似于这个算法复杂度:

O (n <一口> 3> /罢工>

我不是理论专家,所以你可以随意纠正我的假设。事实上,这种复杂性是绝对不能接受的,尤其是考虑到我将在很长的时间范围内与许多地方和人一起工作。

从公式近似中我们可以看到,人的集合将被迭代很多次。因此,我想优化至少这一部分。为了让事情简单一点,我改变了

Person.IList<DateRangePlaces>.IList<Place>

Person.IList<DateRangePlaces>.IDictionary<int, Place>

这将给我一个更快的结果,是否一个人可以去某个地方在特定的日期,因为我只检查Place.Id是否存在于字典中,而IList.Where() LINQ子句每次都必须扫描整个列表。

  1. 你能建议任何额外的优化,我可以实现到我的算法,使它更快,甚至使它在大O符号方面不那么复杂?

  2. 你会在哪里和为什么使用哪种内存结构类型(列表,字典,堆栈,队列…)来提高性能?

附录:整个问题更加复杂

还有额外的复杂性,我没有提到,因为我想简化我的问题,使它更清楚。所以。还有:

Place.IList<Permission>
Person.IList<DateRangePermission>

所以地方需要特定的权限,人们有有限的时间权限授予到期。

除此之外,还有

Person.IList<DateRangeTimingRestriction>

只告诉在特定日期范围内某人可以去某地的特定时间。和

Person.IList<DateRangePlacePriorities>

它定义了特定日期范围的位置优先级。

在寻找合适人选的过程中我还必须计算每个人每个地方的特定因素这与:

  • 一个人在某一天可以访问的地方数量
  • 人员在特定日期的位置优先因素

所有这些都是我决定在内存中操作这些数据的原因,而不是使用一个非常复杂的存储过程,这个存储过程也会做多个表扫描来获取每个人、每个地点和每天的因子。

我认为这样的存储过程处理和维护起来太复杂了。所以我宁愿先得到所有的数据(把它适当的内存结构,以帮助性能),然后在内存中处理它。

高级:如何优化我的复数O(n²)算法

我建议使用关系数据库并编写一个存储过程来检索"适用于地点和日期的人员集"。

如果模型的体系结构正确,那么存储过程方法既不复杂,也不难以维护。此外,关系数据库有主键和索引,以避免表扫描。

使用集合加速的唯一方法是:

  1. 更改收集类型。您可以使用KeyedCollection、dictionary<>,甚至是一个断开连接的记录集。断开连接的记录集还使您能够将外键设置为子记录集,但我认为这将是一个相当复杂的模式使用。

  2. 维护集合中的集合-基本上与带有外键的父/子关系的概念相同。对象引用将仅仅是指向原始对象的内存空间的指针,或者,如果您使用键控集合,您可以简单地存储其他集合的索引。

  3. 维护布尔属性,允许您在true或false时跳过迭代。例如,在构建实体时,设置一个布尔值"hasplacexpmission"。如果该值为false,则不检索与x位置相关的信息。

  4. 维护标志——如果使用得当,标志是一种非常好的优化技术。与#3类似,可以使用标志来快速确定权限,例如,如果((person))。PlacePermissions,(地方。Colorado | Place.Florida)> 0)//对Colorado和Florida做日期/时间扫描,否则不做。

根据您提供的信息很难知道我将使用哪种集合类型,我需要更大的应用程序范围才能从体系结构上确定。例如,数据存储在哪里、如何检索、如何准备以及如何呈现?了解应用程序的架构将有助于确定其优化点。

您无法避免O(n^2),因为您需要的最小迭代是传递每个Place和每个Date元素以找到给定Person的匹配。

我认为最好的方法是使用类似SQL服务器的数据库,并在SQL中运行您的查询作为存储过程。

日期范围大概是相当有限的,可能永远不会超过几年。称之为常数。当你说,对于每一个组合,你需要"得到一组适用的人",那么很明显:如果你真的需要得到所有的数据,那么你就不能提高你的解决方案的复杂性,因为你需要为每个组合返回一个结果。

不要担心复杂性,除非你在与大量人员进行扩展时遇到麻烦。如果遇到性能问题,可以从普通分析开始。O(#locations * #people)还不错