【问题标题】:Writing a merge method for lists为列表编写合并方法
【发布时间】:2011-06-27 06:50:06
【问题描述】:

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

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

谁能指引我正确的方向?什么是“描绘”这个或计划它的好方法,因为我什至不知道从哪里开始。

【问题讨论】:

  • 这听起来像是家庭作业。如果是,您应该提及。
  • @Aidanc:为什么?无论如何,我的回答(我认为詹姆斯的回答)将是相同的。
  • @Fred:为了清楚起见。例如一些学生想找到所有“家庭作业 C++”的问题来自学,或做其他事情
  • @AndyT:自从我第一次听到它以来,我就觉得这很似是而非。对于这些假设的学生:阅读并做各种good books 中的练习,当你感到困惑时提问,并尽可能回答问题(例如这里的 SO)(这几乎完全意味着新的、未回答的问题)。

标签: c++ linked-list


【解决方案1】:

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

当列表之一中仍有元素时循环:

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

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

【讨论】:

  • 你不需要while 循环来处理额外的东西。 list::splice 有另一种形式,它采用列表的beginend 拼接整个范围。
  • @Blastfurnace:好点。 (这显示了我使用std::list 的频率:-P)
【解决方案2】:

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

#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 也很有趣。它允许您同时迭代两个或多个容器。因此,您可以创建一个空列表,并行迭代两个输入列表并将每个输入列表中的一个元素插入到新列表中。

【讨论】:

  • ...但这看起来很讨厌,所有这些 ++ ++ :-S
【解决方案3】:

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

列表:A 最终 B
       0 --> 0
                4  1
                5  2
                6  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);
}

提取拼接会稍微清理一下,但更重要的是,您应该能够为您的(显然是自定义的)列表类型编写以下 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);
}

【讨论】:

    猜你喜欢
    • 2012-11-18
    • 2018-04-26
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多