【问题标题】:Sorted Array vs Hashtable: Which data structure would be more efficient in searching over a range of dates in a calendar app?排序数组与哈希表:在日历应用程序中搜索一系列日期时,哪种数据结构更有效?
【发布时间】:2019-12-29 14:58:03
【问题描述】:

我有大约一年的 Java 编码经验。为了磨练我的技能,我正在尝试用 Java 编写日历/日记条目桌面应用程序。我已经意识到我仍然没有数据持久性方面的经验,并且仍然不真正理解该程序的数据持久性选项是什么——所以也许我在抢先一步,以及我希望的设计选择一旦我进入细节,实施甚至都不适用。

我主要想编写一个日历应用程序,允许您记录日常日记条目以及相关的活动日志,以了解在日常任务上花费的时间。在添加、编辑和查看日志条目方面,使用哈希表,条目的日期作为键,条目本身作为值,似乎是最高效的(O(1) 平均情况,每个使用哈希表)。

不过,我也希望实现一项功能,该功能可以在给定特定日期范围的情况下,提供对每天在特定任务上花费的平均时间量的简单分析。如果这是我感兴趣的主要功能之一,那么我认为排序数组可能会更有效率,我错了吗?特别是考虑到数据条目通常预计已经按日期添加。

或者也许还有其他我不知道的选项?

我问的原因是因为以下问题提供的答案:Why not use hashing/hash tables for everything?

我不确定我是否问对了问题的原因是因为以下问题的答案:Whats the best data structure for a calendar / day planner?

如果是这样,我真的很感激能获得有关 java 数据持久性的其他资源。

感谢您的帮助!

【问题讨论】:

  • 对于只有几个条目的桌面应用程序,我怀疑会有任何显着差异:您的日历中不会有数百万个条目。但是您没有考虑过的一个选项是 TreeMap,它具有 O(log N) 查找/插入时间,并且还允许有效地获取包含一系列条目的子图。不过,我不明白这与坚持有什么关系。这些集合都不是持久的。您需要以某种方式读取它们的元素并将其写入持久存储,但这与您选择使用的集合没有太大关系。
  • 在这种特殊情况下,它们似乎都是 O(N),因为要获取 HashTable 的键,您仍然需要遍历整个表。排序后的数组可能适合您的目标(特别是因为您无法保证在 HashTable 上按排序顺序显示的日期)

标签: java algorithm sorting hashtable data-persistence


【解决方案1】:

使用NavigableMap 接口(由TreeMap 实现,一棵红黑树)。

这使您可以轻松有效地选择日期范围并按关键顺序遍历事件。

顺便说一句,如果您将时间或日期间隔视为"half-open",它将使许多问题变得更容易。也就是说,在选择事件时,在结果中包括下限,但不包括上限。 NavigableMap 的方法,如 subMap(),旨在以这种方式工作,当您处理任意数量的区间时,这是一个很好的做法,因为它很容易定义一个没有重叠或间隙的区间序列。

【讨论】:

  • 对你的“旁白”一千次肯定。
  • 您需要解决的几个问题是:关键是什么?这是活动的开始,还是结束?如果您有两个具有相同开始/结束的事件怎么办?如果您通过 start 键入并想要搜索 end 怎么办? (这并不是说 TreeMap 是一个糟糕的选择;它只是不是灵丹妙药)。
  • @AndyTurner 是的。我假设“事件”被建模为瞬间(关键)和持续时间,以及其他信息。如何处理重叠事件等,需要更多地了解这种特定情况下的需求。
【解决方案2】:

取决于你希望你的项目有多严肃。在所有情况下,请注意过早的优化。这是当您努力使您的代码“高效”并在此过程中牺牲可读性/可维护性时。例如,可能有一种方法可以使用本机代码进行手动内存管理,以更有效地实现日历的数据结构,但它可能不会超过使用熟悉的 API 等的好处。它可能会,但你只知道何时运行代码。

  1. 编写可读代码
  2. 运行它,测试性能问题
  3. 使用分析器(例如 JProfiler)来识别导致性能不佳的代码
  4. 优化该代码
  5. 重复

对于可以“工作”但扩展性不强的代码,简单的List 通常就可以了。您可以使用 JSON 来存储您的对象,并使用诸如 Jackson Databind 之类的库在 List 和 JSON 之间进行映射。然后,您可以简单地将其保存到文件中以保持持久性。

对于您希望更健壮并防止数据损坏的应用程序,数据库可能更好。有了这个,您可以保证,例如,数据不会被部分写入,对相同数据的并发访问不会导致损坏,以及一大堆其他好处。但是,您需要在应用程序旁边运行一个数据库服务器。您可以使用 JDBC 和适合您的数据库供应商(例如 Mysql)的驱动程序来连接、读取和写入数据库。

对于一个严肃的应用程序,您可能希望为您的持久性创建一个 API。像 Spring 这样的框架对此非常有帮助,因为它允许您使用注释声明 REST 端点,并引入有用的编程概念,例如容器、IoC/依赖注入、测试(单元测试和集成测试)、JPA/ORM 系统和更多的。

就像我说的,这完全取决于上下文,但最重要的是,避免过早优化

【讨论】:

  • 正确的数据结构会更快并且提供更好的接口。而且您无需分析代码即可了解不同算法或数据结构的复杂性。我觉得虽然这个答案开始和结束警告不要过早优化,但其中大部分看起来离替代存储甚至架构太远了,这很讽刺。
  • 答案背后的意图是提供一些关于可能的持久性选项的想法(而不是仅针对特定的数据结构),同时强调,在应用程序至少在某种程度上工作之前,可能会有更大的关心的不是使用什么具体的实现。 “提前计划”和“过早优化”之间只有一线之隔,有时我很难将它们区分开来
【解决方案3】:

这个帖子可能会给你一些想法,用于范围查询的数据结构。

Data structure for range query

使用数据库和使用 API 查询所需范围甚至可能更容易。

【讨论】:

    【解决方案4】:

    如果您正在使用(或能够使用)Guava,您可以考虑使用RangeMap (*)。

    这将允许您使用RangeMap<Instant, Event>,然后您可以查询“在时间 T 发生了什么事件”。

    一个缺点是您无法对并发事件进行建模(例如,当您在两次会议中重复预定时)。


    (*) 我在 Google 工作,Guava 是 Google 的开源 Java 库。这是我将使用的库,但也可以使用其他具有类似范围地图产品的库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-07
      • 2020-07-26
      • 2020-06-20
      • 2015-09-01
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      相关资源
      最近更新 更多