如何迭代列表并从中删除?

时间:2014-01-20 16:17:29

标签: c++ c++11 iteration containers

我在使用List迭代器时遇到了很多麻烦,之前我问了一个问题但是无法得到我想要的解决方案。

我有一个循环列表,我必须用节点n +替换节点n的值(步骤)。然后我必须擦除节点n +(步骤)。当我擦除它时,将迭代器放在擦除元素之后的元素中。我需要在节点n处返回迭代器。我怎么能这样做因为每次我擦除n +(步骤)我得到一个无效的迭代器。我的输入是5和2。

如果没有办法从列表中迭代和删除,请告诉我是否有更好的数据结构。我想过使用Vector,但是我必须将元素向下移动,如果有很多元素,那将会很昂贵。

#include "roulette.h"
#include <iostream>

uint roulette(uint people, uint step)
{
    std::list<uint>::iterator iterator;
    for(uint i = people; i > 0; i--)
        gl_myList.push_front(i);

    iterator = gl_myList.begin();
    while(people > 1)
    {
        iterator = advanceList(iterator, step - 1);
        uint replaceValue = *iterator; // Node n's value

        auto tempIterator = advanceList(iterator, step);
        uint newValue = *tempIterator; //Node n + step value

        iterator = gl_myList.erase(tempIterator);
        //Makes it past the erase function ONCE.

        //Puts the iterator back to the correct spot, and sets it value
        while(*iterator != replaceValue)
        {
            advanceList(iterator, 1);

        }
        *iterator = newValue;

        people--;
    }

    return *iterator;
}

advanceList

#include "roulette.h"
std::list<uint>::iterator advanceList(std::list<uint>::iterator& start, uint step)
{
    for(uint i = 0; i < step; i++)
    {
        start++;
        if(start == gl_myList.end())
        {
            start = gl_myList.begin();
        }
    }

    return start;
}

3 个答案:

答案 0 :(得分:2)

您没有正确使用erase()调用的结果,也没有在下一次迭代之前检查.end()。我完全确定以下是你至少试图做的事情。请注意,这仍然是脆弱的,因为它是任何东西,但准备好边缘情况(如初始空列表,0步值等):

std::list<uint>::iterator advanceList(std::list<uint>::iterator& start, uint step)
{
    for(uint i = 0; i < step; i++)
    {
        if(++start == gl_myList.end())
            start = gl_myList.begin();
    }

    return start;
}

uint roulette(uint people, uint step)
{
    std::list<uint>::iterator it;
    for(uint i = people; i > 0; i--)
        gl_myList.push_front(i);

    it = gl_myList.begin();
    while (gl_myList.size() > 1)
    {
        it = gl_myList.erase(advanceList(it, step - 1));
        if (it == gl_myList.end())
            it = gl_myList.begin();
    }

    return *it;
}

答案 1 :(得分:1)

让我们在代码中修复一个非常简单的错误。当你调用

时,advanceList会修改它的参数
auto tempIterator = advanceList(iterator, step);

iteratortempIterator都已更改。这是你想要实现的目标吗?

同样在你的advanceList中,如果您在输入teh功能时开始时已结束,则必须在进入循环之前将其替换为begin

答案 2 :(得分:0)

我相信你没有以正确的方式解决这个问题。

做你想做的事情的最好方法是首先将必须删除的东西与必须保留的东西分开。您可以在标题算法中使用 std :: partition std :: stable_partition 执行此操作。然后,您可以轻松清除容器中的一系列元素。

示例:

#include <vector>
#include <algorithm>
using namespace std;

// ...
bool differentFrom3(int n) { return n != 3; }

vector<int> v = { 1, 3, 4, 2, 1, 3, 4, 3, 7, 3, 1 };

// move all the 3's to one end of the vector
vector<int>::iterator it = stable_partition(v.begin(), v.end(), differentFrom3);

// v is now arranged in the following order:
// { 1, 4, 2, 1, 4, 7, 1, 3, 3, 3, 3 }
//                        ^
//                        +--- it
//
// and it points to the first element whose value is 3 (in this case, v[7])
// Now you can delete everything from the it to the end of the vector.
v.erase(it, v.end());

我在这里使用 stable_partition 因为它保持了元素之间的相对位置。如果您不关心,可以使用分区