为列表编写合并方法

时间:2011-02-14 23:41:54

标签: c++ linked-list

我正在尝试编写一种以交替方式合并双向链表的方法。因此,如果我们有两个int列表(0,1,2,3)和(4,5,6),我们只有一个(0,4,1,5,2,6,3)的最终列表。每个列表都有一个head,一个tail,一个next和一个prev指针。

它试图弄清楚从哪里开始或如何起作用,这让我很伤心。我试图在纸上追踪它,但没有进展。

有人能引导我朝正确的方向前进吗?什么是“描绘”或计划它的好方法,因为我甚至不知道从哪里开始。

3 个答案:

答案 0 :(得分:2)

创建第三个空列表(称为“结果列表”)。

循环,其中一个列表中仍有剩余元素:

  • 如果第一个列表不为空,请从第一个列表的前面弹出一个元素,然后将其推到结果列表的后面。
  • 如果第二个列表不为空,请从第二个列表的前面弹出一个元素,然后将其推到结果列表的后面。

使用C ++ std::list容器看起来像这样(这个算法略有不同,因为在主循环之外处理“额外”元素更容易一些):

template <typename T>
std::list<T> merge_lists(const std::list<T>& a, const std::list<T>& b)
{
    std::list<T> r;
    while (!a.empty() && !b.empty())
    {
        r.splice(r.end(), a, a.begin());
        r.splice(r.end(), b, b.begin());
    }

    r.splice(r.end(), a, a.begin(), a.end());
    r.splice(r.end(), b, b.begin(), b.end());

    return r;
}

答案 1 :(得分:1)

采取以下步骤,沿着每条线向下,用箭头表示移动。例如,在第一步之后,0已从A中删除,最终只有一项:

List:  A      final      B
       0  -->   0
                4   <--  4
       1  -->   1
                5   <--  5
       2  -->   2
                6   <--  6
       3  -->   3

std :: list的一个例子:

std::list<int> A, B;
A.push_back(0); A.push_back(1); A.push_back(2); A.push_back(3);
B.push_back(4); A.push_back(5); A.push_back(6);

std::list<int> final;
for (std::list<int>::iterator a, b;
     (a = A.begin()) != A.end() and (b = B.begin()) != B.end();)
{
  final.splice(final.end(), A, a);
  final.splice(final.end(), B, b);
}
for (std::list<int>::iterator x; (x = A.begin()) != A.end();) {
  final.splice(final.end(), A, x);
}
for (std::list<int>::iterator x; (x = B.begin()) != B.end();) {
  final.splice(final.end(), B, x);
}

提取splice可以清除一些东西,但更重要的是,您应该能够为您的(显然是自定义的)列表类型编写下面的move_back,然后使用它与std :: list:

// Moves pos from source into dest; returns what was the position after
// pos in the source list.
template<class List>
typename List::iterator move_back(List &dest, List &source,
                                              typename List::iterator pos)
{
  typename List::iterator next = pos;
  ++next;
  dest.splice(dest.end(), source, pos);
  return next;
}
template<class List>
void move_back(List &dest, List &source) {
  dest.splice(dest.end(), source, source.begin(), source.end());
}

void example() {
  std::list<int> A, B;
  A.push_back(0); A.push_back(1); A.push_back(2); A.push_back(3);
  B.push_back(4); A.push_back(5); A.push_back(6);

  std::list<int> final;
  for (std::list<int>::iterator a = A.begin(), b = B.end();
       a != A.end() and b != B.end();)
  {
    a = move_back(final, A, a);
    b = move_back(final, B, b);
  }
  move_back(final, A);
  move_back(final, B);
}

答案 2 :(得分:1)

如果您不想更改输入列表,则可以复制第一个列表,然后从其他位置的第二个列表中插入新列表元素。

#include <iostream>
#include <list>
#include <iterator>

int main(int argc, char* argv[])
{
    typedef std::list<int> list;
    list a;  // and fill it ...
    list b;  // and fill that too ...

    list c(a);
    for( list::iterator p(++c.begin()), i(b.begin()); i != b.end(); ++i ) {
        p = ++ ++ c.insert(p, *i);
    }
    return 0;
}

同样令人感兴趣的是Boost Zip Iterator。它允许您同时迭代两个或更多容器。因此,您可以创建一个空列表,并行迭代两个输入列表,并将每个列表中的一个元素插入到新列表中。