【问题标题】:What is the best data-structure for storing elements which will be retrieved only once and then deleted?存储只会检索一次然后删除的元素的最佳数据结构是什么?
【发布时间】:2011-02-28 17:37:48
【问题描述】:

我想设计一个数据结构来存储元素,插入后只检索一次,然后删除。

我不能使用堆栈或队列,因为无法保证检索顺序。

[编辑] - 我想使用连续内存(我宁愿避免不时地做 malloc),而且我也更喜欢可搜索性。

【问题讨论】:

  • 不。我想使用连续内存,我希望我可以使用比线性搜索更好的东西。
  • 很不清楚你的检索顺序是什么......你能详细说明一下吗?
  • 您打算存储的元素类型是什么?
  • @Jay - 如果插入/检索的顺序不同步,那么你的连续内存不会连续很长时间。
  • “检索”是什么意思?您的 cmets 似乎表明您的要求比您在问题中写的要多。您需要可搜索性吗?您希望结构缩小/增长还是固定大小?此外,您应该提到您希望在问题本身中使用连续的内存。 (也许也解释一下你为什么想要那个。)

标签: c data-structures


【解决方案1】:

我认为算法的选择需要更多关于如何使用它的信息。根据您想要比线性搜索更好的评论,我假设搜索速度很重要。您在连续内存上的 cmets 让我相信您希望最大程度地减少内存消耗。我建议自平衡树结构 (Red-Black tree) 可能是合适的。它将摊销 log(N) 插入/删除,使您能够实现我概述的两个目标。如果内存使用问题不大,则哈希表的查找效率会更高。您可以在连续内存中实现有界大小的树——尽管实际元素本身不一定是连续的。

另一方面,如果我知道插入的顺序是随机的,但检索的顺序是确定性的并按键排序,那么我可能会建议使用堆实现的priority queue

【讨论】:

    【解决方案2】:

    将存储需求与数据结构分开。

    您说您想要连续的内存 - 我假设您想要获取一块内存并完全在该内存中工作,而不是随着时间的推移分配更多的片段。

    现在最简单的情况是在内存块中通过环形缓冲区实现队列。我假设你想要更好的东西,因为你没有在这里发生 fifo。

    因此,某种形式的平衡树听起来像是您所需要的。选择可能取决于到达键的模式。随机的?上升?

    一个问题是从你的块中分配内存,而不是使用普通的堆分配器,这可能意味着也要保留一个空闲列表。

    知道为什么你重视一块连续的内存会很有趣。

    【讨论】:

      【解决方案3】:

      花园品种链表可以满足您的要求。但是细化您的要求会产生更好的建议。

      例如:

      1. 速度重要吗?链表会注入搜索时间和分配/释放开销。
      2. 您是否担心内存碎片?随着时间的推移,具有大量插入/删除活动的链表会严重分散内存。
      3. 数据集的界限是什么?如果您期望数据集相对有限,那么命中表可能比可以增长到任意大小的链表更好。

      【讨论】:

      • 另外:您更关心插入速度还是检索速度?你不会得到两者。
      【解决方案4】:

      可能是哈希表或某种树。由于您要进行大量删除操作,因此如果您使用哈希表,它(几乎)需要通过链接来处理冲突。

      假设所有元素的大小都相同,您可能还需要考虑编写自己的代码来分配元素,以便在元素被删除后轻松重用空间。

      编辑:IMO,你可能想要一个链表。虽然链表使删除本身保持恒定速度,但查找元素是线性的,因此总体速度为 O(N + K) = O(N)。对于哈希表,预期速度为 O(1),而对于树则为 O(lg N)。

      【讨论】:

        【解决方案5】:

        显然是双向链表。 “你希望你的记忆是连续的”是什么意思?无论您使用哪种数据结构,它只会在您删除一个元素之前是连续的,之后您必须将数据打包以保持连续性。严重的是,当您需要在每次删除后平均移动一半的记录时,您使用哪种数据结构几乎无关紧要,无论如何您都搞砸了。只需使用动态数组即可。

        【讨论】:

          【解决方案6】:

          使用red-black treememory pool 从连续的内存块分配项目。 Sample implementations of red-black trees written in C are readily available。大多数应该很容易修改以支持自定义内存分配器,如果它们还没有提供该功能。

          【讨论】:

            【解决方案7】:

            听起来您想要最普遍的数据结构——数组。在您的情况下,是动态分配的,类似于 C++ std::vector 类提供的。

            【讨论】:

              【解决方案8】:

              您可以使用(双)链表并仍然保持您的记忆连续。

              分配一大块内存来保存所有节点,并跟踪您为数据存储分配了哪些节点。

              您有多种管理预分配内存的选项。

              一种方法是使用可用节点的队列或堆栈,您可以取出一个空闲节点,写入数据并将其添加到链表中。当你完成一个节点时,将它从链表中删除,然后放回队列/堆栈中。

              根据您的堆栈/队列实现,这可能相当于维护两个链表。稍加思考就可以产生一种高效且简洁的数据结构和底层代码设计。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-09-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多