拆分STL列表?

时间:2014-04-07 04:48:50

标签: c++ algorithm stl

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

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实现此算法是否有效?或者我应该放弃并编写自己的循环链表库?

谢谢!

1 个答案:

答案 0 :(得分:2)

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

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;
}

有两种选择:

  • 撤消列表中的内部部分(3 2 5
  • 撤消外部部分(0 1 -> 4

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

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

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

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

是恒定时间。

检查live example