2

我向你展示我的问题

我有 2 个列表,分别命名为 A 和 B。

list<vector<int> > A = {{1},{2},{3}};
list<vector<int> > B = {{4},{5},{6}}; 

我想要的是 A = {{1,4},{1,5},{1,6},{2,4},{2,5},{2,6},{3,4} ,{3,5},{3,6}} 不使用任何 tmp 列表。

我在 Ubuntu 12.04 上使用 C++11 和 gcc 4.6.3

这样最小化代码:

auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i); // A[i]
        copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
        A.emplace_back(tmp); //add it to A
    }
}
A.erase(A_begin,A_end); // remove {1},{2},{3}

所以,我认为算法没问题,但它会在 A 上创建一个无限循环。我认为当我创建 A.emplace_back 时 A_end 会发生变化,但我保存了它,所以我真的不知道这里追加。

我的代码来识别问题:

auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();

int ii = A.size();

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i);
        A.emplace_back(tmp);
    }
    cout<<--ii<<endl; // exit when print 0 ?
}

这个打印负数,我必须再次^C。

编辑:我找到了解决方案:

auto A_begin = A.begin();
auto A_end =  A.end();
auto B_begin = B.begin();
auto B_end = B.end();

list<vector<int>> tmp_l;

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i); // A[i]
        copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
        tmp_l.emplace_back(move(tmp)); //add it to A
    }
}
 swap(tmp_l,A);
4

3 回答 3

2

这两行:

vector<int> tmp = (*i); // A[i]
copy((*j).begin(),(*j).end(),tmp.end()); // append B[j] to A[i]

将调用未定义的行为。通过复制到 tmp.end(),您只是在 A[i] 结束后覆盖内存,而不是扩展 A[i]。您需要使用 back_insert 迭代器,例如:

vector<int> tmp = (*i); // A[i]
copy((*j).begin(), (*j).end(), back_inserter(tmp)); // append B[j] to A[i]

您还需要包含标题以获取 back_inserter。

编辑:此外,A_end 迭代器指向列表的“结束”位置,因此无论您添加多少项目,它们总是添加在 A_end 前面,因此是无限循环。我不确定是否有解决此问题的好方法。不创建临时列表没有任何好处,无论哪种方式,您都在分配相同的内存,只需写入一个新列表即可。

于 2013-01-18T13:13:21.510 回答
1

你的算法不好。

这 :

copy((*j).begin(),(*j).end(),tmp.end());

会导致各种问题,因为您覆盖了一些随机内存。

您可能想做这样的事情来追加:

vector<int> tmp = (*i);
copy((*j).begin(),(*j).end(),std::back_inserter(tmp));
于 2013-01-18T13:07:48.077 回答
1

编辑:我找到了解决方案:

该解决方案很好,使用临时向量并将其交换比原地执行要好A,因为您的原始版本(以及复制到向量末尾)以从头开始移动每个元素的方式完成。erase

但是您的解决方案可以改进:

// get rid of these iterators, they're useless
/*
auto A_begin = A.begin();
auto A_end =  A.end();
auto B_begin = B.begin();
auto B_end = B.end();
*/

list<vector<int>> tmp_l;

// use new for loops
for (auto& a : A)
{
    for (auto& b : B)
    {
// use auto
        auto tmp = a; // A[i]
// I find just inserting at the end simpler than using `back_inserter`
        tmp.insert(tmp.end(), b.begin(), b.end()); // append B[j] to A[i]
// then clear it the moved-from elements:
        b.clear();
// move the tmp vector into place, do not copy it.
        tmp_l.emplace_back(std::move(tmp));
    }
}
swap(tmp_l,A);
于 2013-01-18T14:01:09.010 回答