【问题标题】:Splitting an STL list?拆分 STL 列表?
【发布时间】:2014-04-07 04:48:50
【问题描述】:

我有一个看起来像这样的循环链表:

4 -> 3 -> 2 -> 5 -> 0 -> 1 -> beginning

我想将此列表分成两段,反转其中一段,然后重新加入列表。像这样的:

拆分,O(1) 操作 4 ** 3 -> 2 -> 5 ** 0 -> 1 -> beginning

反向,O(n) 操作 0 ** 3 -> 2 -> 5 ** 4 -> 1 -> beginning

重新加入,O(1) 操作 0 -> 3 -> 2 -> 5 -> 4 -> 1 -> beginning

STL 似乎没有循环链表,但我希望我可以将列表表示为(前向)列表。这需要: * 一种将列表拆分为子列表的方法 * 一种将列表合并在一起的方法

使用std::list::splice 将子列表合并在一起应该很容易,并且应该是 O(1) 操作。耶!

但是,我找不到一个好的 O(1) 方法将列表拆分为子列表。 One approach 是使用迭代器,但我认为这在我的情况下不起作用,因为子列表离开列表的末尾并在列表的开头恢复。

有没有一种使用 STL 实现该算法的有效方法?还是干脆放弃写自己的循环链表库?

谢谢!

【问题讨论】:

  • 如果你的总操作是O(N),为什么你希望你的拆分操作是O(1)?根据这个链接,没有标准的循环链表实现。stackoverflow.com/questions/947489/…
  • 最后,我想让我的程序尽可能快。 O(N) split + O(N) reverse 会比 O(1) split + O(N) reverse 慢。另外,我很确定我可以总是颠倒最短的子列表,所以希望在这种情况下 N 很小。
  • 这是用于 TSP 的吗?您可能需要一个两级树而不是链表,这将运行时间减少到 O(sqrt(n)),而没有二叉树的大常数因子 (O(log(n)))。
  • @JohnSaxton 我不认为拆分操作可以是链表中的 O(1) 操作。这是因为您首先需要到达“拆分节点”,然后传输“下一个”指针。这个“到达”操作是一个 O(N) 操作。
  • @JohnSaxton O(0) 用于拆分怎么样,不要拆分您的列表,只需使用 const 迭代器列表到每个子列表的开头进行逻辑拆分,然后在到达时停止下一个迭代器 :) 并且对于反向,您可以围绕枢轴进行反射交换(如果所选子列表的大小为奇数则不存在

标签: c++ algorithm stl


【解决方案1】:

我不确定这有多大帮助,但这里是:

template<typename I>
void inner(I b, I e)
{
    std::reverse(b, e);  // l = {4 5 2 3 0 1}
}

template<typename L, typename I>
void outer(L& l, I b, I e)
{
    l.splice(l.begin(), l, e, l.end());  // l = {0 1 4 3 2 5}
    std::reverse(l.begin(), b);          // l = {4 1 0 3 2 5}
}

int main ()
{
    std::list<int> t, l{4, 3, 2, 5, 0, 1};
    std::cout << l << std::endl;

    auto b = l.begin(), e = l.begin();
    std::advance(b, 1);
    std::advance(e, 4);
    bool in = true;

    in ? inner(b, e) : outer(l, b, e);
    std::cout << l << std::endl;
}

有两种选择:

  • 反转列表的 inner 部分 (3 2 5)
  • 反转外部部分 (0 1 -&gt; 4)

并且您可能想要反转较短的,但您必须计算这一点,这是线性时间。我为这两个任务编写了两个单独的函数inner,outer

inner 非常简单(只是一个包装器)并且按预期工作。但是,outer 使列表处于与预期的模数旋转(循环移位)等效的状态。如果您正在建模一个循环列表,这应该没问题。但是,如果您希望输出与示例中的完全相同,则必须再次计数,以找到正确的旋转点。我会避免这种情况,因为它是线性时间。

请注意,实际上不需要拆分,因为反转是就地的。还有,操作

l.splice(l.begin(), l, e, l.end());

是常数时间。

检查live example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多