【问题标题】:Can STL algorithms be used with circular lists?STL 算法可以与循环列表一起使用吗?
【发布时间】:2014-06-02 10:17:00
【问题描述】:

为您的自定义列表创建一个符合 STL 的迭代器非常简单。

然而,如果引用列表是一个循环列表,这似乎毫无意义,因为所有 STL 算法都在[first, last) 范围和循环列表first = last 中运行。

是否有标准/一致的方法来克服这个障碍,并让 STL 算法在“自制”循环列表上运行?

我认为定义符合 STL 的迭代器是实现这一目标的第一步,但也可能有一个可以在范围内操作的解决方案。


我需要为大量的“自制”结构实现这一点。我目前的解决方案是从boost::iterator_facade 派生,然后创建一个自定义range 类(如Rudolph's)并使用围绕基于范围的执行的任何算法。这仍然存在一些逻辑障碍,并且希望看到可行的替代方案和/或解决方案。

【问题讨论】:

  • 这仅在您在循环列表中定义 end() 时有效。如果你能够做到这一点,并且从 begin() 迭代可以让你到达那里,我认为没有任何问题。
  • 你可以有两种不同类型的迭代器,一种实现环绕,另一种实现通常的语义。
  • 您会发现这样做的一个主要障碍是循环列表对“第一个”和“最后一个”是什么具有上下文相关的想法。从列表中的两个不同位置作为“第一个”开始将使用两个不同的“最后一个”概念。这听起来微不足道,但实际上它很快就会变得一团糟。

标签: c++ algorithm stl


【解决方案1】:

您将需要自定义迭代器,但解决方案仍然可以基于范围。 一种可能性是begin() 可以返回一个特别标记的迭代器(标志initial=true),以便它知道它还没有完成这一轮。 end() 将返回一个将该标志设置为 false 的迭代器。然后operator++ 将标志设置为false,这样begin() 将不等于end()。您也可以使用不同的标记方案。

【讨论】:

  • 不幸的是,这只适用于“只读”迭代器。这种方法的基本问题是,在迭代过程中,初始节点可能会被删除,因此 both begin() end() 可能会失效,而end()无法重新评估。
【解决方案2】:

我对 STL 及其迭代器的理解与您的提议不一致。 C++ 标准库中的迭代器(众所周知)具有指针的语义。它们不换行,end() 不等于 begin()

作为指针的类似物,迭代器指向缓冲区中的一个位置。你不能指望一个天真的调用者的线性复制操作在最后回绕。这将通过算法和其他库应用。据我所知,它们根本无法按预期工作。

我完全没有理由不使用 STL 集合和迭代器,但我认为你不应该期望(或强制)it++ 进行换行。我宁愿认为您需要清晰可见的成员函数来实现您需要的附加功能。

例如,您可以有一个递增迭代器的incr() 函数,但如果它指向end(),则返回到开头。您可以有一个 copy() 函数,该函数了解如何在包装的缓冲区中提取或插入数据块。

但是我不明白你的其他限制,所以这可能不适合你。我认为这对我有用。

【讨论】:

  • 当然,您不能指望线性复制操作适用于所有容器吗?以链表或地图为例。
  • @Skizz:我可能会更好地表达,但如果first===lastcopy(first,last,result) 肯定行不通。
【解决方案3】:

说在许多算法中(我不是在谈论 STL,而是在一般情况下)在内部数据结构中插入一个空叶或空元素以提高性能,我觉得在你的循环列表中保留一个空/null元素可以解决问题。

  • 显然,null 元素的位置不是固定的,它会根据您的数据流移动。
  • 同时,您将保持数据结构中的最后 N 个样本(大小为 N + 1 个空元素)连续。
  • 这使得[first,last)first != last 的范围成为可能。
  • null 元素是 last 指向的元素,它是下一次插入发生的地方。
  • 每次插入时,一旦容器中有 N 个元素,first 指向的元素将被“无效化”,first 会递增。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 2013-09-14
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 2022-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多