【问题标题】:STL list, delete all the odd numbersSTL列表,删除所有奇数
【发布时间】:2015-05-13 09:01:30
【问题描述】:

我正在尝试学习如何使用 STL,并尝试编写一个函数来接收对列表的引用并尝试删除所有奇数成员。 我的代码有一个小问题。这是我的代码

void removeOdds(list<int>& myvector)
{
    for(list<int>::iterator p=myvector.begin(); p !=myvector.end();p++)
    {
        if(*p%2 !=0)
        {
            list<int>::iterator temp=myvector.erase(p);
            p=temp;
            if(p !=myvector.begin())
                p--;
        }
    }
}

我遇到的问题是,例如,如果我传递一个包含 1 3 5 2 6 7 的列表。删掉1后明显跳到5了,不看3了。 我该如何解决这个问题,因为 p++ 会增加,而 p-- 不会发生,因为我在开始。

【问题讨论】:

  • [OT]:我会避免为std::list 调用参数myvector(因为std::vector 存在)。 myInts`

标签: c++ stl


【解决方案1】:

最简单的方法是使用std::list::remove_if。这会根据一元谓词从列表中删除元素。例如,

myvector.remove_if([](int n) { return n % 2 != 0; });

使用“STL”* 的最佳方法是了解其中的内容。

对于 C++11 之前的实现(例如实际的 STL),您可以传递一个函数:

bool is_odd(int n) { return n % 2 != 0; }

myvector.remove_if(is_odd);

*"STL" 表示 STL,但这也适用于 C++ 标准库

【讨论】:

  • 确实如此,但我正在尝试熟悉这个概念并学习如何操作迭代器等,所以我想在没有 remove_if 函数的情况下这样做。
  • @user1335175 你说你“试图学习如何使用 STL”,所以。
【解决方案2】:

方法 erase 将迭代器返回到删除后的下一个元素。因此,完成此类任务的通常方法如下

void removeOdds( std::list<int> &myvector )
{
    for ( auto it = myvector.begin(); it != myvector.end();  )
    {
        if ( *it % 2 !=0 )
        {
            it = myvector.erase( it );
        }
        else
        {
            ++it;
        }
    }
}

至于你的代码,循环语句总是增加迭代器

for(list<int>::iterator p=myvector.begin(); p !=myvector.end();p++)
                                                               ^^^^  

考虑到类 std::list 具有方法 removeremove_if,它们会删除所有满足给定条件的元素。

这是一个展示这两种方法的演示程序

#include <iostream>
#include <list>

void removeOdds( std::list<int> &myvector )
{
    for ( auto it = myvector.begin(); it != myvector.end();  )
    {
        if ( *it % 2 !=0 )
        {
            it = myvector.erase( it );
        }
        else
        {
            ++it;
        }
    }
}

int main()
{
    std::list<int> l = { 1, 3, 5, 2, 6, 7 };

    for ( auto x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    removeOdds( l );

    for ( auto x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    l = { 1, 3, 5, 2, 6, 7 };

    for ( auto x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    l.remove_if( []( int x ) { return x % 2; } );

    for ( auto x : l ) std::cout << x << ' ';
    std::cout << std::endl;
}

程序输出是

1 3 5 2 6 7 
2 6 
1 3 5 2 6 7 
2 6 

【讨论】:

    【解决方案3】:

    好的,我找到了一种方法,那就是将 p++ 从 for 循环声明移到其中,就像这样。

    void removeOdds(list<int>& myvector)
    {
        for(list<int>::iterator p=myvector.begin(); p !=myvector.end();)
        {
            if(*p%2 !=0)
            {
                list<int>::iterator temp=myvector.erase(p);
                p=temp;
            }
            else
                p++;
        }
    } 
    

    现在我很好奇我是否可以这样做并且仍然保持我的 for 循环完好无损。

    【讨论】:

    • “保持我的 for 循环完好无损”是什么意思?
    • 注意可以直接做p = myvector.erase(p);
    • 保持for循环不变,我的意思是保持与我在问题中显示的方式相同。
    • @user1335175 你的循环比调用remove_if 效率低。此外,remove_if 保证无需进一步检查即可正常工作,任何称职的 C++ 程序员都了解它的作用等。另一方面,必须有人检查您的循环并对其进行测试,看看是否有任何陷阱等, 在它被认为是声音之前。因此,真的很少需要“保持循环完整”。保持循环不会给您带来任何好处,只会导致问题。
    【解决方案4】:

    既然你在学习,你最好忘记'C'的做事方式,直接跳入C++11。

    这是您使用现代 C++ 编写的代码

    void removeOdds(vector<int>& myvector)
    {
        auto new_end = std::remove_if (myvector.begin(), myvector.end(), 
         [](const auto& value){ return value%2 !=0 }
        );    
        myvector.erase(new_end, myvector.end());
    }
    

    就您的代码而言,只需使用 auto 就可以大大提高可读性 请注意,在容器上循环时删除元素是有风险的。向量通常没问题,但当你开始使用其他数据结构时,事情就变得更糟糕了。

    【讨论】:

    • 我认为这不是一个好的解决方案,因为存在更高效的 1-liner。另外,没有std::erase,但也许你的意思是myvector.erase
    • 是的,你是对的,它是 vector.erase。但是,请提供一个更高效的单班轮示例。这具有线性复杂性,鉴于给定问题的性质,我很确定您无法超越。
    • 嗯,这是我的答案,这是第一个在这里发布的。 时间复杂度是否是线性的并不重要。您必须执行两次,一次重新排列列表,另一次删除元素。 std::list 没有理由这样做。
    • 我会建议你为这两种解决方案计时。带有列表的那个会慢几个数量级。另外,没有两次pass,擦除只是改变向量的一些内部状态,不需要再次扫描向量。列表的有用范围确实、非常、非常有限,但出于某种原因,这就是他们在学校/大学教授的内容,人们一直坚持使用它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 2017-02-06
    相关资源
    最近更新 更多