【C++之STL】012序列容器篇list更易型操作

c.push_back()

在C++的std::list容器中,push_back()成员函数用于在链表的尾部插入一个新元素。push_back()函数接受一个参数,该参数是你想要添加到链表末尾的值。

下面是一些使用push_back()函数的示例:

#include <iostream>
#include <list>

int main() {
    // 创建一个空的std::list<int>
    std::list<int> myList;

    // 使用push_back()在链表尾部插入元素
    myList.push_back(10);
    myList.push_back(20);
    myList.push_back(30);

    // 遍历链表并打印元素
    for (const auto& element : myList) {
        std::cout << element << ' ';
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

10 20 30

在这个例子中,我们创建了一个空的std::list,然后使用push_back()函数三次向链表中添加整数。最后,我们使用基于范围的for循环遍历链表并打印出每个元素。

push_back()函数的时间复杂度是常数时间,也就是说,无论链表的大小如何,它都可以在常量时间内完成操作。这是因为链表是一个双向链表,它可以在O(1)时间内直接访问其尾部。

值得注意的是,push_back()函数不会返回任何值,因为它是一个void函数。

c.pop_back()

在C++的std::list容器中,pop_back()成员函数用于删除链表的最后一个元素。换句话说,它移除链表的尾部元素。如果链表是空的,调用pop_back()将会导致未定义行为,通常是程序崩溃。

下面是一些使用pop_back()的示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 向链表中添加一些元素
    myList.push_back(10);
    myList.push_back(20);
    myList.push_back(30);

    // 打印链表中的元素
    std::cout << "Before pop_back(): ";
    for (const auto& element : myList) {
        std::cout << element << ' ';
    }
    std::cout << std::endl;

    // 删除链表的最后一个元素
    myList.pop_back();

    // 再次打印链表中的元素
    std::cout << "After pop_back(): ";
    for (const auto& element : myList) {
        std::cout << element << ' ';
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

Before pop_back(): 10 20 30 
After pop_back(): 10 20

在这个例子中,我们首先创建了一个空的std::list,然后向其中添加了三个元素。接着,我们打印出链表中的所有元素,然后调用pop_back()删除最后一个元素(即30)。最后,我们再次打印链表中的所有元素,可以看到最后一个元素已经被删除。

注意:在实际使用中,通常建议在调用pop_back()之前检查链表是否为空,以避免未定义行为。这可以通过使用empty()成员函数来实现:

if (!myList.empty()) {
    myList.pop_back();
}

这样,只有当链表不为空时,才会调用pop_back()。

c.push_front()

在C++的std::list容器中,push_front()成员函数用于在链表的开头插入一个新元素。这意味着新元素将被添加到链表的第一个位置,成为链表的第一个元素。

下面是push_front()函数的一些使用示例:

#include <iostream>
#include <list>

int main() {
    // 创建一个空的std::list<int>
    std::list<int> myList;

    // 使用push_front()在链表开头插入元素
    myList.push_front(10);
    myList.push_front(20);
    myList.push_front(30);

    // 遍历链表并打印元素
    for (const auto& element : myList) {
        std::cout << element << ' ';
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

30 20 10

在这个例子中,我们创建了一个空的std::list,然后使用push_front()函数三次向链表中添加整数。每次调用push_front()时,新元素都被添加到链表的开头。最后,我们使用基于范围的for循环遍历链表并打印出每个元素。

push_front()函数的时间复杂度是常数时间,即O(1),因为链表可以在其头部直接插入新元素,而不需要移动其他元素。

与push_back()类似,push_front()也不会返回任何值,因为它是一个void函数。如果你需要知道新插入元素的迭代器位置,你可能需要使用emplace_front()或insert()函数,这些函数可以返回新插入元素的迭代器。

例如,使用emplace_front()插入元素并获取其迭代器:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 使用emplace_front()在链表开头插入元素并获取迭代器
    auto it = myList.emplace_front(40);

    // 通过迭代器打印新插入的元素
    std::cout << "Newly inserted element: " << *it << std::endl;

    return 0;
}

输出将是:

Newly inserted element: 40

在这个例子中,emplace_front()函数在链表的开头就地构造了一个新元素,并返回了一个指向它的迭代器。然后,我们使用这个迭代器来打印新插入的元素。

c.pop_front()

在C++的std::list容器中,push_front()成员函数用于在链表的开头插入一个新元素。这意味着新元素将被添加到链表的第一个位置,成为链表的第一个元素。

下面是push_front()函数的一些使用示例:

#include <iostream>
#include <list>

int main() {
    // 创建一个空的std::list<int>
    std::list<int> myList;

    // 使用push_front()在链表开头插入元素
    myList.push_front(10);
    myList.push_front(20);
    myList.push_front(30);

    // 遍历链表并打印元素
    for (const auto& element : myList) {
        std::cout << element << ' ';
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

30 20 10

在这个例子中,我们创建了一个空的std::list,然后使用push_front()函数三次向链表中添加整数。每次调用push_front()时,新元素都被添加到链表的开头。最后,我们使用基于范围的for循环遍历链表并打印出每个元素。

push_front()函数的时间复杂度是常数时间,即O(1),因为链表可以在其头部直接插入新元素,而不需要移动其他元素。

与push_back()类似,push_front()也不会返回任何值,因为它是一个void函数。如果你需要知道新插入元素的迭代器位置,你可能需要使用emplace_front()或insert()函数,这些函数可以返回新插入元素的迭代器。

例如,使用emplace_front()插入元素并获取其迭代器:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 使用emplace_front()在链表开头插入元素并获取迭代器
    auto it = myList.emplace_front(40);

    // 通过迭代器打印新插入的元素
    std::cout << "Newly inserted element: " << *it << std::endl;

    return 0;
}

输出将是:

Newly inserted element: 40

在这个例子中,emplace_front()函数在链表的开头就地构造了一个新元素,并返回了一个指向它的迭代器。然后,我们使用这个迭代器来打印新插入的元素。

c.insert()

在C++中,std::list的insert()函数用于在链表的指定位置插入一个或多个元素。insert()函数有多种重载形式,以适应不同的插入需求。下面是一些示例,展示了如何使用insert()函数:
示例1:插入单个元素

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // 在链表的第3个位置(索引为2)之前插入一个元素9
    myList.insert(myList.begin() + 2, 9);

    // 输出链表的内容
    for (int num : myList) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:1 2 9 3 4 5

示例2:插入多个相同元素

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // 在链表的第4个位置(索引为3)之前插入3个元素,每个元素的值都是7
    myList.insert(myList.begin() + 3, 3, 7);

    // 输出链表的内容
    for (int num : myList) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:1 2 3 7 7 7 4 5

示例3:插入另一个容器的元素

#include <iostream>
#include <list>
#include <vector>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};
    std::vector<int> vec = {6, 7, 8};

    // 在链表的末尾插入vector中的所有元素
    myList.insert(myList.end(), vec.begin(), vec.end());

    // 输出链表的内容
    for (int num : myList) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:1 2 3 4 5 6 7 8

在所有这些示例中,insert()函数接受一个迭代器,该迭代器指向要插入新元素的位置。对于单个元素的插入,还需要提供要插入的值。对于多个相同元素的插入,还需要提供元素的数量和值。如果要插入另一个容器的元素,需要提供该容器的开始和结束迭代器。

c.emplace()

在 C++ 中,std::list 是一个双向链表容器,它允许我们在链表的任何位置进行高效的插入和删除操作。std::list 提供了多种成员函数来操作链表,其中 emplace() 是一个常用的成员函数,用于在链表的特定位置就地构造并插入一个元素。

emplace() 函数接受一组参数,这些参数用于直接构造新元素,而不是首先构造一个临时对象然后再将其复制到链表中。这样做的好处是避免了不必要的复制和可能的性能开销。

下面是 std::list::emplace() 的基本用法示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 使用 push_back 插入元素
    myList.push_back(10);
    myList.push_back(20);
    myList.push_back(30);

    // 输出原始链表
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // 使用 emplace 在链表末尾插入新元素
    myList.emplace_back(40);

    // 输出更新后的链表
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // 使用 emplace 在链表的特定位置插入新元素
    myList.emplace(myList.begin() + 1, 50);

    // 输出更新后的链表
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出:

10 20 30 
10 20 30 40 
10 50 20 30 40

在上面的示例中,我们首先创建了一个包含三个整数元素的 std::list。然后,我们使用 emplace_back() 在链表的末尾插入了一个新元素。接着,我们使用 emplace() 在链表的第二个位置(myList.begin() + 1)插入了一个新元素。

注意,emplace() 函数需要提供一个迭代器,该迭代器指示新元素应该插入的位置。在这个例子中,我们使用 myList.begin() + 1 来指示新元素应该插入到链表的第二个位置。

c.emplace_back()

在 C++ 中,std::list 提供了一个成员函数 emplace_back(),它用于在列表的尾部就地构造并插入一个新元素。emplace_back() 类似于 push_back(),但 emplace_back() 更高效,因为它直接在列表的尾部构造元素,而不需要先创建一个临时对象然后再将其复制到列表中。

使用 emplace_back() 可以避免不必要的拷贝和构造函数的调用,这通常可以提高性能,尤其是对于资源密集型的对象。

下面是一个使用 emplace_back() 的示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 使用 emplace_back 插入新元素
    myList.emplace_back(10);
    myList.emplace_back(20);
    myList.emplace_back(30);

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

10 20 30

在这个例子中,我们创建了一个 std::list 类型的列表 myList,然后使用 emplace_back() 函数向列表的尾部插入了三个整数元素。每个 emplace_back() 调用都在列表的尾部直接构造了一个新元素,并将其添加到列表中。

对于更复杂的类型,emplace_back() 尤其有用,因为它允许你传递构造函数所需的参数,而不是先构造一个对象。例如,如果你有一个自定义的类,并且它的构造函数接受多个参数,你可以使用 emplace_back() 来避免不必要的临时对象创建。

例如,对于一个自定义的类 Person:

class Person {
public:
    Person(std::string name, int age) : name(name), age(age) {}
    // ... 其他成员 ...
private:
    std::string name;
    int age;
};

int main() {
    std::list<Person> people;

    // 使用 emplace_back 插入新元素,直接构造 Person 对象
    people.emplace_back("Alice", 30);
    people.emplace_back("Bob", 25);

    // ... 其他代码 ...

    return 0;
}

在这个例子中,我们直接在 emplace_back() 中传递了 Person 构造函数所需的参数,从而避免了先创建一个 Person 对象再进行拷贝的开销。

c.emplace_front()

在 C++ 中,std::list 提供了一个成员函数 emplace_front(),它用于在列表的前端就地构造并插入一个新元素。与 push_front() 函数类似,emplace_front() 函数在列表的开头插入一个新元素,但 emplace_front() 更高效,因为它直接在列表的前端构造元素,而不需要先创建一个临时对象然后再将其插入到列表中。

使用 emplace_front() 可以避免不必要的拷贝和构造函数的调用,这通常可以提高性能,尤其是对于资源密集型的对象。

下面是一个使用 emplace_front() 的示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 使用 emplace_front 插入新元素
    myList.emplace_front(10);
    myList.emplace_front(20);
    myList.emplace_front(30);

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

30 20 10

在这个例子中,我们创建了一个 std::list 类型的列表 myList,然后使用 emplace_front() 函数向列表的前端插入了三个整数元素。每个 emplace_front() 调用都在列表的前端直接构造了一个新元素,并将其添加到列表中。

对于更复杂的类型,emplace_front() 尤其有用,因为它允许你传递构造函数所需的参数,而不是先构造一个对象。例如,如果你有一个自定义的类 Person:

class Person {
public:
    Person(std::string name, int age) : name(name), age(age) {}
    // ... 其他成员 ...
private:
    std::string name;
    int age;
};

int main() {
    std::list<Person> people;

    // 使用 emplace_front 插入新元素,直接构造 Person 对象
    people.emplace_front("Alice", 30);
    people.emplace_front("Bob", 25);

    // ... 其他代码 ...

    return 0;
}

在这个例子中,我们直接在 emplace_front() 中传递了 Person 构造函数所需的参数,从而避免了先创建一个 Person 对象再进行拷贝的开销。

c.erase()

在C++中,std::list容器提供了erase()成员函数,用于删除列表中的一个或多个元素。erase()函数可以接受一个或两个迭代器参数,以确定要删除的元素范围。

下面是erase()函数的一些用法示例:
删除单个元素

如果要删除列表中的一个特定元素,可以传递指向该元素的迭代器给erase()函数。例如:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // 假设我们要删除值为3的元素
    auto it = std::find(myList.begin(), myList.end(), 3);
    if (it != myList.end()) {
        myList.erase(it); // 删除找到的元素
    }

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

1 2 4 5

删除一系列元素

如果要删除一系列元素,可以传递两个迭代器给erase()函数,分别表示要删除范围的开始和结束位置。例如:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // 假设我们要删除从值为2的元素开始到值为4的元素结束的所有元素
    auto start_it = std::find(myList.begin(), myList.end(), 2);
    auto end_it = std::find(myList.begin(), myList.end(), 4);
    if (start_it != myList.end() && end_it != myList.end()) {
        myList.erase(start_it, end_it); // 删除找到的范围内的元素
    }

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

1 5

注意,在使用erase()函数时,如果迭代器指向的元素不在列表中(即,it == myList.end()),则会导致未定义行为。因此,在调用erase()之前,通常要检查迭代器是否有效。

此外,erase()函数会使所有指向被删除元素的迭代器、引用和指针失效。因此,在调用erase()之后,不应该继续使用这些失效的迭代器、引用或指针。

c.remove()

在 C++ 标准库中,std::list 有一个 remove() 成员函数,用于删除所有等于给定值的元素。remove() 函数会遍历列表,并删除所有等于指定值的元素。这个函数会直接修改列表,不需要额外的 erase 调用。

以下是 std::list::remove() 的用法示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 2, 4, 2, 5};

    // 假设我们要删除所有值为2的元素
    myList.remove(2);

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

1 3 4 5

如你所见,所有值为 2 的元素都被从列表中删除了。

std::list::remove() 的函数签名如下:

void remove(const value_type& val);

这里,value_type 是列表中元素的类型。函数接受一个参数,即要删除的值,并遍历整个列表,删除所有与这个值相等的元素。

需要注意的是,std::list::remove() 只有在列表已经排序的情况下才能保证删除所有等于给定值的元素。如果列表未排序,那么只能删除连续出现的等于给定值的元素。对于未排序的列表,如果你想删除所有等于给定值的元素,你可能需要首先对列表进行排序,或者使用 std::remove_if 算法配合 std::list::unique 和 std::list::erase。

c.remove_if()

在 C++ 中,std::list 容器确实提供了一个 remove_if 成员函数,这个函数用于删除满足特定条件的所有元素。remove_if 接受一个谓词(一个返回布尔值的函数或函数对象),并对列表中的每个元素调用这个谓词。如果谓词对某个元素返回 true,那么这个元素就会被从列表中删除。

下面是一个使用 std::list::remove_if 的例子:

#include <iostream>
#include <list>
#include <algorithm>

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

    // 假设我们要删除所有偶数元素
    myList.remove_if([](int n) { return n % 2 == 0; });

    // 输出列表中的元素
    for (const auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

1 3 5 7 9

在这个例子中,remove_if 函数接受了一个 lambda 表达式作为参数,这个 lambda 表达式检查一个整数是否是偶数。对于列表中的每个元素,如果 lambda 表达式返回 true,则该元素会被删除。

需要注意的是,remove_if 函数会改变列表的大小,并且不会返回任何值。它直接修改了传入的列表,删除了所有使谓词返回 true 的元素。因此,调用 remove_if 之后,列表将只包含不满足谓词条件的元素。

与 std::remove 算法不同,std::list::remove_if 是容器成员函数,它直接在容器上操作,不需要额外的 erase 调用。另外,std::remove 需要列表是排序的,而 std::list::remove_if 则没有这个要求。

  • 31
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊猫Devin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值