【问题标题】:Idea for a data structure to store 2D data?存储二维数据的数据结构的想法?
【发布时间】:2013-06-21 16:00:28
【问题描述】:

我有一个大的 2D 网格,x-by-y。应用程序的用户将添加有关此网格上特定点的数据。不幸的是,网格太大而无法实现为大型 x×y 数组,因为运行它的系统没有足够的内存。

什么是实现这一点的好方法,以便只有添加了数据的点才存储在内存中?

我的第一个想法是创建数据点的 BST。诸如“(long)x

然后我得出结论,如果不平衡,这可能会降低效率,因此我想出了一个由可比较的 BST 点组成的 BST 的想法。外部 BST 将根据 x 值比较内部 BST。内部 BST 将通过它们的 y 值来比较这些点(并且它们都将具有相同的 x)。因此,当程序员想要查看 (5,6) 处是否有一个点时,他们会在外部 BST 中查询 5。如果在该点存在内部 BST,那么程序员将在内部 BST 中查询 6。结果将被退回。

你能想出更好的实现方式吗?

编辑:关于 HashMaps:大多数 HashMaps 需要有一个用于查找的数组。有人会说“data[hash(Point)] = Point();”设置一个点,然后通过散列找到该点以找到索引。然而,问题是数组必须是散列函数范围的大小。如果此范围小于添加的数据点总数,则它们将没有空间或必须添加到溢出中。因为我不知道要添加的点数,所以我必须假设这个数字会小于某个数量,然后将数组设置为该大小。同样,这会实例化一个非常大的数组(尽管如果假设数据点比 x*y 少,则比最初的要小)。我希望结构随着数据量线性扩展,并且在为空时不会占用大量数据。

正如一些人所提到的,我想要的是一个 SparseArray。它们的实现方式是否类似于在 BST 中包含 BST?

Edit2: Map 是一个接口。如果我要使用地图,那么看起来 TreeMap 将是最好的选择。所以我最终会得到 TreeMap>,类似于人们提出的 Map > 建议,这基本上是 BST 中的 BST。不过,感谢您提供的信息,因为我不知道 TreeMap 基本上是 BST 的 Java SDK。

Edit3:对于那些可能关心的人来说,选择的答案是最好的方法。首先,必须创建一个包含 (x,y) 并实现可比较的 Point 类。该点可能会通过类似 (((long)x)

总之,这允许稀疏数组的空间效率和搜索效率的实现,或者在我的例子中,二维数组也可以有效地迭代。

【问题讨论】:

  • 不要重新发明轮子,看看空间数据结构
  • 您似乎对数据结构的底层实现更感兴趣,而不是您将如何使用它。如果您需要一些空间查询(x 在 10 到 40 之间的点)或最近邻查询,您可以使用 AlexWien 提到的一些结构,或一些可导航的地图。如果您只需要查找某个特定点,那么普通的旧 HashMap 会做得很好 - docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
  • @Kiril Raychev:添加点后,我计划使用结构中的所有数据进行计算,但不需要范围查询。
  • 好的,看来地图最适合您的使用。但是当你开始考虑空间问题时,可以考虑使用不基于对象的 HashMap,这样可以节省 60% 的内存空间。 (点对象与原始类型)

标签: java data-structures


【解决方案1】:

Quadtreek-d-treeR-tree

将大点数组的索引存储到空间结构之一中。 如果数据分布不均,这种空间结构是有利的,例如集中在城市中的地理数据,在海洋中没有意义。

想想您是否可以忘记常规网格,并继续使用四叉树。
(想一想,为什么需要规则网格?规则网格通常只是一种简化)

在任何情况下都不要使用对象来存储点。 这样的对象只需要 20 个字节,因为它是一个对象!对于庞大的数据集来说是个坏主意。

int x[]int[] yint[]xy 数组是与内存使用相关的理想选择。

考虑阅读

Hanan Samet“多维数据结构的基础”

(至少是引言)。

【讨论】:

  • @AndreaLigios,是的,与您的旧实现相比,通过这些,您可以将性能提高 100 到 1000 倍
  • 这些结构很好,但四叉树不是最好的,因为我的数据排列在离散的行和列中,而不是分布在二维连续域中的点,而这正是四叉树的设计目的。感谢您的回答!
  • 四叉树不是为连续坐标设计的。它用于整数坐标,通常是 2 的幂。如此离散。四叉树是一个索引,而不是存储本身。它曾经以最小的努力找到附近的点。您可以将数据存储为品脱 (row, col) 或 (x,y)。您的数据是否均匀分布或聚集在某些位置?
  • 我也推荐使用类似于此处提到的树结构来保持空间相关性,而使用哈希表方法会丢失这些信息。
【解决方案2】:

您可以使用Map<Pair, Whatever> 来存储您的数据(您必须编写 Pair 类)。如果您需要以特定顺序迭代数据,请配对Comparable,并使用NavigableMap

【讨论】:

  • +1 好的解决方案;打败我 :) 我也喜欢提到NavigableMap
  • 为什么不直接使用Point 类?
  • @splunebob 你的意思是java.awt.Point?我认为使用旨在用于某些完全不同目的的类总是一个坏主意,只是因为它们具有正确的属性。 awt 点是可变的,可以用双精度设置,并且可以应用转换——这完全不是我们需要的。
  • @KirilRaychev:很好的解释。
  • @ReedB 是的,你可以。推荐的方法是迭代 entrySet 而不是 keySet,因为它更有效,但两者都可以。
【解决方案3】:

一种方法是Map<Integer, Map<Integer, Data>>。外层映射的键是行值,内层映射的键是列值。与该内部映射关联的值(在这种情况下为Data 类型)对应于(row, column) 处的数据。当然,如果您正在考虑尝试进行矩阵运算等,这将无济于事。为此,您需要稀疏矩阵。

另一种方法是将行和列表示为Coordinate 类或Point 类。您将需要实现equalshashCode(应该非常简单)。然后,您可以将您的数据表示为Map<Point, Data>Map<Coordinate, Data>

【讨论】:

    【解决方案4】:

    您可以拥有一个对象列表的列表,并且该对象可以对其水平和垂直位置进行编码。

    class MyClass
    {
        int x;
        int y;
        ...
    }
    

    【讨论】:

    • 但是每次添加一个新对象时,因为我想拥有一组唯一的点,我必须搜索所有数据的列表以查看它之前是否已经存在更新数据点或添加新数据点。我试图避免这个低效的过程。
    • @ReedB 并没有那么低效,特别是如果您有一个 列表列表,其中外部列表​​对应于x,内部列表对应于y。搜索将是 O(x+y) 时间复杂度
    【解决方案5】:

    也许我在这里太简单了,但我认为您可以使用普通的HashMap。它将包含自定义 Point 对象作为键:

    class Point {
        int x;
        int y;
    }
    

    然后您将基于xy 的equals 方法(以及hashCode 方法)重写。这样你只存储有一些数据的点。

    【讨论】:

      【解决方案6】:

      我认为你在正确的轨道上以一种内存有效的方式执行此操作 - 它可以通过使用映射的映射相当容易地实现,包装在一个类中以提供一个干净的查找接口。

      另一种(更节省内存)方法是使用单个映射,其中键是元组 (x,y)。但是,如果您需要进行诸如“给我x == some value 的所有值”之类的查询,这将不太方便。

      【讨论】:

      • 地图的地图看起来很有希望。正如我在其他几个 cmets 中所说的那样,如果我使用一个 Map 是 TreeMap,那么它必须根据从两点生成的某种散列值来比较节点,就像我最初对单个 BST 的想法一样.如果这个 Map 是一个线性 Map,比如一个列表,那么这将是非常低效的,因为每次我想添加数据时,我都必须在更新列表或添加之前线性搜索列表以查看它是否已经存在新数据点。
      【解决方案7】:

      您可能想查看 Matrix toolkit project 中的 FlexCompColMatrix、CompColMatrix 和其他稀疏矩阵实现。

      性能实际上取决于写入/读取比率和矩阵的密度,但是如果您使用的是矩阵包,则通过切换实现来进行实验会更容易

      【讨论】:

        【解决方案8】:

        我给你的建议是使用Commons Math: The Apache Commons Mathematics Library。因为它可以利用您的应用程序所需的数学力量来节省您的时间。

        【讨论】:

          猜你喜欢
          • 2012-06-02
          • 1970-01-01
          • 2018-12-02
          • 1970-01-01
          • 1970-01-01
          • 2011-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多