C/C++编程:STL list的使用

1059 篇文章 280 订阅

概述

  • list<>由双向链表实现而成。这意味着list内的每个元素都以一部分内存指示其前导元素和后继元素
  • list<>不提供随机访问,因此如果你要访问第10个元素,必须沿着链表依次走过前9个元素
  • list<>的优势是:在任何位置上执行安插或者删除动作都非常快速,因为只需要改变链接就好

构造函数&&析构函数

 

非更易型操作

赋值操作 

 

元素访问

 

 

 

迭代器

 

 

插入&&删除

 

 

 

 

Splice(接和)函数以及会改变元素次序的函数

 

 

异常处理

 

 

 

 

实例

构造

#include <list>
#include <string>
#include <iostream>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::list<T>& v)
{
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    // C++11 初始化器列表语法:
    std::list<std::string> words1 {"the", "frogurt", "is", "also", "cured"};
    std::cout << "words1: " << words1 << '\n';

    // words2 == words1
    std::list<std::string> words2(words1.begin(), words1.end());
    std::cout << "words2: " << words2 << '\n';

    // words3 == words1
    std::list<std::string> words3(words1);
    std::cout << "words3: " << words3 << '\n';

    // words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::list<std::string> words4(5, "Mo");
    std::cout << "words4: " << words4 << '\n';
    return 0;
}

std::list<T,Allocator>::operator=、std::list<T,Allocator>::assign

  • std::list<T,Allocator>::assign作用:替换容器的内容
  • std::list<T,Allocator>::operator=作用:替换容器的内容
#include <list>
#include <string>
#include <iostream>

void display_sizes(const std::list<int>& nums1,
                   const std::list<int>& nums2,
                   const std::list<int>& nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::list<int> nums1 {3, 1, 4, 6, 5, 9};
    std::list<int> nums2;
    std::list<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);



    return 0;
}

#include <list>
#include <string>
#include <iostream>



int main()
{
    std::list<char> characters;

    characters.assign(5, 'a');

    for (char c : characters) {
        std::cout << c << ' ';
    }

    characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});

    for (char c : characters) {
        std::cout << c;
    }

    return 0;
}

front、back

  • std::list<T,Allocator>::front:返回到容器首元素的引用。在空容器上调用 front 会引发未定义行为

  • std::list<T,Allocator>::back:返回到容器中最后一个元素的引用。在空容器上调用 back 会引发未定义行为

#include <list>
#include <iostream>

int main()
{
    std::list<char> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
        std::cout << "The last character is: " << letters.back() << '\n';
    }
}

begin、end、rbegin、rend

  • begin:返回指向list首元素的迭代器
  • end:   返回指向 list 末元素后一元素的迭代器。
#include <iostream>
#include <numeric>
#include <list>
#include <string>

int main()
{
    std::list<int> nums {1, 2, 4, 8, 16};
    std::list<std::string> fruits {"orange", "apple", "raspberry"};
    std::list<char> empty;

    // 求和 list nums 中的所有整数(若存在),仅打印结果。
    std::cout << "Sum of nums: " <<
        std::accumulate(nums.begin(), nums.end(), 0)  << "\n";

    // 打印 list fruits 中的首个 fruis
    if(!fruits.empty()){
        std::cout << "First fruit: " << *fruits.begin() << "\n";
    }

    if (empty.begin() == empty.end())
        std::cout << "list 'empty' is indeed empty.\n";
}

empty、size、max_size、resize

  • empty:检查容器是否为空
  • size:返回容器中的元素数,相当于 std::distance(begin(), end())
  • max_size:返回最大可以容纳的元素个数

  • resize:重设容器大小以容纳count个元素

#include <list>
#include <iostream>
 
int main()
{
    std::list<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';
 
    numbers.push_back(42);
    numbers.push_back(13317); 
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

#include <list>
#include <iostream>
#include <limits>

int main()
{
    std::list<int> numbers;
    std::cout << "max size: " << numbers.max_size() << '\n';
    std::cout << "max size: " << std::numeric_limits<std::list<int>>::max().max_size()<< '\n';
}

#include <iostream>
#include <list>
int main()
{
    std::list<int> c = {1, 2, 3};
    std::cout << "The list holds: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(5);
    std::cout << "After resize up to 5: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(2);
    std::cout << "After resize down to 2: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
}

swap

#include <list>
#include <iostream>

template<class Os, class Co>
Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

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

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    int & ref1 = a1.front();
    int & ref2 = a2.front();
    
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与其原来的元素关联,例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素,
    // 尽管此元素被移动到 'a2' 中。
}

效果

#include <algorithm>
#include <iostream>
#include <list>
 
int main()
{
    std::list<int> alice{1, 2, 3};
    std::list<int> bob{7, 8, 9, 10};
 
    auto print = [](const int& n) { std::cout << " " << n; };
 
    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
 
    std::cout << "-- SWAP\n";
    std::swap(alice,bob);
 
    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

效果

clear、erase

  • clear:从容器擦除所有元素。此调用后 size() 返回零。
  • erase:从容器擦除指定的元素

  • 1) 移除位于 pos 的元素。
  • 2) 移除范围 [first; last) 中的元素。
#include <algorithm>
#include <iostream>
#include <list>

int main()
{
    std::list<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

#include <list>
#include <iostream>
#include <iterator>
 
int main( )
{
    std::list<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
 
    c.erase(c.begin());
 
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
 
    std::list<int>::iterator range_begin = c.begin();
    std::list<int>::iterator range_end = c.begin();
    std::advance(range_begin,2);
    std::advance(range_end,5);
 
    c.erase(range_begin, range_end);
 
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
}

#include <iostream>
#include <numeric>
#include <list>
 
void print_container(const std::list<char>& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}
 
int main()
{
    std::list<char> cnt(10);
    std::iota(cnt.begin(), cnt.end(), '0');
 
    std::cout << "Init:\n";
    print_container(cnt);
 
    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);
 
    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

emplace、emplace_front、push_back

  • emplace:直接于pos前插入元素到容器中
  • emplace_front、push_front:插入新元素到容器起始
  • emplace_back、push_back:插入新元素到容器末尾

  • pop_back:移除容器的末元素。在空容器上调用 pop_back 导致未定义行为。指向被擦除元素的迭代器和引用被非法化。
#include <algorithm>
#include <iostream>
#include <list>

struct A{
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::list<A> container;

    std::cout << "construct 2 times A:\n";
    A two { "two" };
    A three { "three" };

    std::cout << "emplace:\n";
    container.emplace(container.end(), "one");

    std::cout << "emplace with A&:\n";
    container.emplace(container.end(), two);

    std::cout << "emplace with A&&:\n";
    container.emplace(container.end(), std::move(three));

    std::cout << "content:\n";
    for (const auto& obj : container)
        std::cout << ' ' << obj.s;
    std::cout << '\n';
}

#include <list>
#include <iostream>
 
template<class T>
void print(T const & xs)
{
    std::cout << "[ ";
    for(auto && x : xs) {
        std::cout << x << ' ';
    }
    std::cout << "]\n";
}
 
int main()
{
    std::list<int> numbers;
 
    print(numbers); 
 
    numbers.push_back(5);
    numbers.push_back(3);
    numbers.push_back(4);
 
    print(numbers); 
 
    numbers.pop_back();
 
    print(numbers); 
}

merge

  • merge:归并两排序链表为一个

#include <iostream>
#include <list>
 
std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}
 
int main()
{
    std::list<int> list1 = { 5,9,0,1,3 };
    std::list<int> list2 = { 8,7,2,6,4 };
 
    list1.sort();
    list2.sort();
    std::cout << "list1:  " << list1 << "\n";
    std::cout << "list2:  " << list2 << "\n";
    list1.merge(list2);
    std::cout << "merged: " << list1 << "\n";
}

splice

  • splice:从一个list转移元素给另一个。不复制或者移动元素,仅重指向链表节点的内部指针

#include <list>
#include <iostream>

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::list<int> list1 = { 1, 2, 3, 4, 5 };
    std::list<int> list2 = { 10, 20, 30, 40, 50 };

    auto it = list1.begin();
    std::advance(it, 2);

    list1.splice(it, list2);

    std::cout << "list1: " << list1 << "\n";
    std::cout << "list2: " << list2 << "\n";

    list2.splice(list2.begin(), list1, it, list1.end());

    std::cout << "list1: " << list1 << "\n";
    std::cout << "list2: " << list2 << "\n";
}

remove, remove_if

#include <list>
#include <iostream>
 
int main()
{
    std::list<int> l = { 1,100,2,3,10,1,11,-1,12 };
 
    l.remove(1); // 移除两个等于 1 的元素
    l.remove_if([](int n){ return n > 10; }); // 移除全部大于 10 的元素
 
    for (int n : l) {
        std::cout << n << ' '; 
    }
    std::cout << '\n';
}

reverse

  • 作用:逆转容器中的元素顺序。不非法化任何引用或迭代器。
#include <iostream>
#include <list>
 
std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}
 
int main()
{
    std::list<int> list = { 8,7,5,9,0,1,3,2,6,4 };
 
    std::cout << "before:     " << list << "\n";
    list.sort();
    std::cout << "ascending:  " << list << "\n";
    list.reverse();
    std::cout << "descending: " << list << "\n";
}

unique

  • 从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素。
#include <iostream>
#include <list>
 
int main()
{
  std::list<int> x = {1, 2, 2, 3, 3, 2, 1, 1, 2};
 
  std::cout << "contents before:";
  for (auto val : x)
    std::cout << ' ' << val;
  std::cout << '\n';
 
  x.unique();
  std::cout << "contents after unique():";
  for (auto val : x)
    std::cout << ' ' << val;
  std::cout << '\n';
 
  return 0;
}

比较

#include <iostream>
#include <list>
 
int main()
{
    std::list<int> alice{1, 2, 3};
    std::list<int> bob{7, 8, 9, 10};
    std::list<int> eve{1, 2, 3};
 
    std::cout << std::boolalpha;
 
    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';
 
    std::cout << '\n';
 
    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

如果想要扩展list的功能

看个例子:

#include <list>
#include <type_traits>



template<typename T>
class List : public std::list<T> {
public:
    template<typename ... ARGS>
    List(ARGS &&...args) : std::list<T>(std::forward<ARGS>(args)...) {};

    ~List() = default;

    void append(List<T> &other) {
        if (other.empty()) {
            return;
        }
        this->insert(this->end(), other.begin(), other.end());
        other.clear();
    }

    template<typename FUNC>
    void for_each(FUNC &&func) {
        for (auto &t : *this) {
            func(t);
        }
    }

    template<typename FUNC>
    void for_each(FUNC &&func) const {
        for (auto &t : *this) {
            func(t);
        }
    }
};

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当准备面试时,精通C/C++编程是非常重要的。以下是一些关键的主题和技巧,可以帮助你在C/C++编程面试中脱颖而出: 1. 基础知识:熟悉C/C++的基本语法、数据类型、运算符、控制流程等基础知识是必须的。还需要了解指针、引用、内存管理等底层概念。 2. 数据结构和算法:掌握常见的数据结构(如数组、链表、栈、队列、树、图等)和算法(如排序、查找、递归、动态规划等)。能够分析算法的时间复杂度和空间复杂度,并能够选择合适的数据结构和算法解决问题。 3. 内存管理:了解堆和栈的区别,掌握动态内存分配和释放的方法(如malloc/free、new/delete),避免内存泄漏和悬挂指针等问题。 4. 面向对象编程:熟悉面向对象编程的概念和特性,如封装、继承、多态等。了解虚函数、纯虚函数、虚析构函数等相关知识。 5. 异常处理:掌握异常处理机制,了解try-catch块的使用和异常的传递机制。能够合理地处理异常,保证程序的稳定性和可靠性。 6. 多线程编程:了解多线程编程的基本概念和常用的线程同步机制(如互斥锁、条件变量、信号量等)。熟悉线程的创建、销毁和同步操作。 7. STL库:熟悉C++标准模板库(STL)的常用容器(如vector、list、map等)和算法(如排序、查找、遍历等)。能够灵活运用STL提供的功能,提高开发效率。 8. 编译和调试:了解编译过程和常见的编译器选项。熟悉调试工具的使用,能够定位和修复程序中的错误。 9. 项目经验:准备一些自己在C/C++开发中的项目经验,包括项目的规模、所用到的技术和解决的问题等。能够清晰地表达自己在项目中的角色和贡献。 10. 实践和练习:通过实践和练习来提高自己的编程能力。参与开源项目、解决编程问题、刷题等都是很好的方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值