[C++语法]-list(用法详解及实现)

1. list的介绍

1.1 list的介绍

关键特点:

  1. list确实有一个哨兵节点(空节点)

    • 不存储有效数据

    • 用于简化边界条件处理

  2. begin() 指向哨兵节点的下一个节点

    • 即第一个实际存储数据的节点

    • 如果list为空,begin() == end()

  3. end() 指向哨兵节点

    • 哨兵节点不存储数据

    • 不能解引用 end()(因为它是尾后位置)

  • 循环链表 :哨兵节点的 prev 指向最后一个节点,next 指向第一个节点

  • 简化操作:插入、删除等操作不需要特殊处理头尾情况

  • 迭代器稳定:在list中插入/删除不会使其他迭代器失效(除了被删除元素的迭代器)

1.2 list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已 达到可扩展的能力。以下为list中一些常见的重要接口。

1.2.1 list的构造

|-----------------------------------------------------------|-----------------------------|
| 构造函数( (constructor)) | 接口说明 |
| list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的 元素 |
| list() | 构造空的list |
| list (const list& x) | 拷贝构造函数 |
| list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造 list |

示例代码:

1. list(size_type n, const value_type& val = value_type())

cpp 复制代码
// 创建n个相同的val
std::list<int> a(4, 5);    // 4个5: {5,5,5,5}
std::list<char> b(3, 'A'); // 3个'A': {'A','A','A'}

2. list()

cpp 复制代码
// 创建空列表
std::list<int> emptyList;  // {}

3. list(const list& x)

cpp 复制代码
// 复制另一个list
std::list<int> original = {1,2,3};
std::list<int> copy(original);  // {1,2,3}

4. list(first, last)

cpp 复制代码
// 从其他容器复制数据
std::vector<int> vec = {5,6,7,8};
std::list<int> lst(vec.begin(), vec.end()-1);  // {5,6,7}

1.2.2 list iterator的使用

大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。

不懂迭代器的同学可以看一下[C++语法]-string类(用法详解及实现)-CSDN博客的2.2疑难解答部分。

|---------------|--------------------------------------------------------------------------|
| 函数声明 | 接口说明 |
| begin + end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位 置的reverse_iterator,即begin位置 |

【注意】

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

1.2.3 list capacity

|-------|-------------------------------|
| 函数声明 | 接口说明 |
| empty | 检测list是否为空,是空返回true,否则返回false |
| size | 返回list中有效节点的个数 |

简单示例:

cpp 复制代码
#include <iostream>
#include <list>

int main() {
    // 1. empty() - 检查list是否为空
    std::list<int> lst1;           // 空list
    std::list<int> lst2 = {1, 2};  // 非空list
    
    std::cout << "lst1.empty(): " << lst1.empty() << std::endl;  // true (1)
    std::cout << "lst2.empty(): " << lst2.empty() << std::endl;  // false (0)
    
    // 2. size() - 获取元素个数
    std::list<int> lst3 = {10, 20, 30, 40, 50};
    std::cout << "lst3.size(): " << lst3.size() << std::endl;  // 5
    
    return 0;
}

实际应用:

cpp 复制代码
// 清空list
std::list<int> nums = {1, 2, 3, 4, 5};

while (!nums.empty()) {
    std::cout << "当前大小: " << nums.size() << std::endl;
    nums.pop_front();  // 逐个删除元素
}

std::cout << "清空后大小: " << nums.size() << std::endl;  // 0

1.2.4 list element access

cpp 复制代码
#include <iostream>
#include <list>

int main() {
    std::list<int> lst = {10, 20, 30, 40, 50};
    
    // 1. front() - 获取第一个元素
    std::cout << "第一个元素: " << lst.front() << std::endl;  // 10
    
    // 2. back() - 获取最后一个元素  
    std::cout << "最后一个元素: " << lst.back() << std::endl;  // 50
    
    // 3. 可以修改元素
    lst.front() = 100;  // 修改第一个元素
    lst.back() = 500;   // 修改最后一个元素
    
    std::cout << "\n修改后: ";
    for (int n : lst) {
        std::cout << n << " ";  // 100 20 30 40 500
    }
    
    return 0;
}

1.2.5 list modifiers

|------------|------------------------------------------------|
| 函数声明 | 接口说明 |
| push_front | 在list首元素前插入值为val的元素(val 的类型就是 list 里存储的元素类型) |
| pop_front | 删除list中第一个元素 |
| push_back | 在list尾部插入值为val的元素 |
| pop_back | 删除list中最后一个元素 |
| insert | 在list position 位置中插入值为val的元素 |
| erase | 删除list position位置的元素 |
| swap | 交换两个list中的元素 |
| clear | 清空list中的有效元素 |

1. push_front(val) - 头部插入

cpp 复制代码
std::list<int> lst = {2, 3};
lst.push_front(1);  // 开头插入1 → {1, 2, 3}

2. pop_front() - 头部删除

cpp 复制代码
std::list<int> lst = {1, 2, 3};
lst.pop_front();   // 删除1 → {2, 3}

3. push_back(val) - 尾部插入

cpp 复制代码
std::list<int> lst = {1, 2};
lst.push_back(3);  // 末尾插入3 → {1, 2, 3}

4. pop_back() - 尾部删除

cpp 复制代码
std::list<int> lst = {1, 2, 3};
lst.pop_back();    // 删除3 → {1, 2}

5. insert(pos, val) - 指定位置插入

cpp 复制代码
std::list<int> lst = {1, 3};
auto it = lst.begin();
++it;  // 指向3
lst.insert(it, 2);  // 在第二个位置插入2 → {1, 2, 3}

6. erase(pos) - 指定位置删除

cpp 复制代码
std::list<int> lst = {1, 2, 3};
auto it = lst.begin();
++it;  // 指向2
lst.erase(it);  // 删除2 → {1, 3}

7. swap(other) - 交换两个list

cpp 复制代码
std::list<int> a = {1, 2};
std::list<int> b = {3, 4};
a.swap(b);  // a = {3, 4}, b = {1, 2}

8. clear() - 清空list

cpp 复制代码
std::list<int> lst = {1, 2, 3};
lst.clear();  // lst = {}

1.2.6 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

cpp 复制代码
void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array+sizeof(array)/sizeof(array[0]));
    auto it = l.begin();
    while (it != l.end())
   {
   // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
    l.erase(it);  
    ++it;
   }
}
// 改正
void TestListIterator()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array+sizeof(array)/sizeof(array[0]));
    auto it = l.begin();
    while (it != l.end())
   {
    l.erase(it++);    // it = l.erase(it);
   }
}

学会了就给博主点个赞呗?(✪ω✪)

---------(如有问题,欢迎评论区提问)---------

相关推荐
雨季6664 小时前
构建 OpenHarmony 简易文字行数统计器:用字符串分割实现纯文本结构感知
开发语言·前端·javascript·flutter·ui·dart
雨季6664 小时前
Flutter 三端应用实战:OpenHarmony 简易倒序文本查看器开发指南
开发语言·javascript·flutter·ui
进击的小头4 小时前
行为型模式:策略模式的C语言实战指南
c语言·开发语言·策略模式
Aevget4 小时前
MFC扩展库BCGControlBar Pro v37.2新版亮点:控件功能进一步升级
c++·mfc·界面控件
天马37984 小时前
Canvas 倾斜矩形绘制波浪效果
开发语言·前端·javascript
Tansmjs4 小时前
C++与GPU计算(CUDA)
开发语言·c++·算法
qx094 小时前
esm模块与commonjs模块相互调用的方法
开发语言·前端·javascript
Suchadar5 小时前
if判断语句——Python
开发语言·python
莫问前路漫漫6 小时前
WinMerge v2.16.41 中文绿色版深度解析:文件对比与合并的全能工具
java·开发语言·python·jdk·ai编程
九皇叔叔6 小时前
【03】SpringBoot3 MybatisPlus BaseMapper 源码分析
java·开发语言·mybatis·mybatis plus