【问题标题】:Best Data Structure to Store Large Amounts of Data with Dynamic and Non-unique Keys?使用动态和非唯一键存储大量数据的最佳数据结构?
【发布时间】:2010-06-18 22:37:16
【问题描述】:

基本上,我有大量的 C 结构要跟踪,它们基本上是:

struct Data {
    int key;
    ...        // More data
};

我需要定期访问其中的很多(数百个),并且它们必须从最低到最高 key 值排序。密钥不是唯一的,它们将在程序过程中更改。更有趣的是,大多数结构将在排序之前从池中剔除(基于与键值完全无关的标准),但我仍然需要保留对它们的引用。

我研究过使用二叉搜索树来存储它们,但不能保证键是唯一的,而且我不完全确定如何在更改键后重新构建树或如何剔除特定结构。

回顾一下上面不清楚的情况,我需要:

  1. 存储大量具有非唯一键和动态键的结构。
  2. 剔除大部分结构(但不要完全释放它们,因为每次都会剔除不同的结构)。
  3. 将剩余的结构按键值从高到低排序。

您会使用什么数据结构/算法来解决这个问题?该方法需要尽可能快和/或内存效率高,因为这是一个实时应用程序。

编辑:剔除是通过遍历所有对象并为每个对象做出决定来完成的。剔除/分类运行之间的键会发生变化。我应该说它们没有太大变化,但它们确实发生了变化,并且它们可以在剔除/排序运行之间多次更改。 (如果有帮助,每个结构的关键实际上是 Sprite 的 z 顺序。它们需要在每个绘图循环之前进行排序,以便首先绘制 z 顺序较低的 Sprite。)

【问题讨论】:

  • 了解键更改的频率会有所帮助:在剔除/排序运行之间的时间里,键的更改比例是多少?他们会改变不止一次吗?
  • 另外,剔除是如何完成的?您是否遍历所有对象并对每个对象做出决定?
  • 您当然可以实现一棵二叉树,其中键被保证是唯一的。插入时,无论如何您都必须将树向下移动,因此当您到达新密钥所在的位置时,请确保插入点处的密钥与您要插入的密钥不相等。

标签: data-structures


【解决方案1】:

只需将它们全部放在一个大阵列中即可。

到了进行剔除和排序的时候,从排序开始。进行插入排序。没错 - 没什么聪明的,只是一个插入排序。

排序后,遍历排序后的数组,对每个对象做出剔除决策,如果没有剔除则立即输出。

这与内存效率差不多。它还应该需要很少的计算:在剔除/排序传递之间没有记录更新,并且排序会很便宜 - 因为插入排序是自适应的,对于像这样的几乎排序的数组,它几乎是 O(n) .它不做的一件事是缓存局部性:将在数组上进行两次单独的传递,用于排序和剔除/输出。

如果您要求更聪明,那么您可以使用另一种更快的自适应就地排序来代替插入排序。 Timsort 和smoothsort 是不错的选择;两者都非常难以实施。

对此的最大替代方案是仅对未剔除的对象进行排序,使用您排序的此类对象的辅助临时列表(或保存在二叉树或其他中)。但问题是,如果键没有太大变化,那么在几乎排序的数组上使用自适应排序所获得的胜利将(我认为!)超过排序较小数据集所获得的胜利。这是 O(n) 与 O(n log n)。

【讨论】:

    【解决方案2】:

    这类问题的一般解决方案是使用平衡搜索树(例如 AVL 树、红黑树、B-树),它保证 O(log n) 时间(几乎恒定,但不完全)插入、删除和查找,其中 n 是当前存储在树中的项目数。保证没有键在树中存储两次是很简单的,并且由许多实现自动完成。

    如果您使用 C++,您可以尝试使用 std::map<int, yourtype>。如果在 C 中,找到或实现一些简单的二叉搜索树代码,看看它是否足够快。

    但是,如果您使用这样的树并发现它太慢,您可以研究一些更精细的方法。一种可能是将您的结构放入一个大数组中,radix sort 通过整数键,对其进行剔除,然后在每次传递时重新排序。另一种方法可能是使用 Patricia 树。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多