C++ STL: list使用及源码剖析

list使用

list常用函数及使用(1) 

#include <iostream>
#include <list>
#include <algorithm>int main() {// 创建liststd::list<int> myList = {5, 2, 9, 1, 5, 6};// 打印liststd::cout << "Original list: ";for(auto i = myList.begin(); i != myList.end(); ++i) {std::cout << *i << ' ';}std::cout << '\n';// 检查list是否为空,然后获取大小if (!myList.empty()) {std::cout << "List is not empty and has size: " << myList.size() << '\n';}// 访问第一个和最后一个元素std::cout << "First element: " << myList.front() << '\n';std::cout << "Last element: " << myList.back() << '\n';// 向list前后插入元素myList.push_front(0);myList.push_back(10);// 删除第一个和最后一个元素myList.pop_front();myList.pop_back();// 在list中插入元素auto it = std::find(myList.begin(), myList.end(), 5);if (it != myList.end()) {myList.insert(it, 4); // 在第一个5之前插入4}// 删除一个特定的元素myList.remove(2); // 删除所有的2// 对list进行排序myList.sort();// 删除所有连续重复的元素myList.unique();// 打印修改后的liststd::cout << "Modified list: ";for(const auto& elem : myList) {std::cout << elem << ' ';}std::cout << '\n';return 0;
}

list常用函数及使用(2) 

#include <iostream>
#include <list>
#include <algorithm>int main() {// 初始化两个liststd::list<int> list1 = {1, 2, 3, 4, 5};std::list<int> list2 = {6, 7, 8, 9, 10};// 使用splice将list2的元素转移到list1的末尾list1.splice(list1.end(), list2);// 使用remove删除所有的'3'list1.remove(3);// 使用remove_if删除所有偶数list1.remove_if([](const int& value) { return value % 2 == 0; });// 创建第三个list用于merge操作std::list<int> list3 = {11, 12, 13};list1.sort(); // 确保merge前list1是排序的list3.sort(); // 确保merge前list3是排序的list1.merge(list3);// 使用reverse反转list1list1.reverse();// 使用swap交换list1和list2的元素list1.swap(list2);// 使用resize调整list1的大小list1.resize(3);// 使用clear清空list2list2.clear();// 使用rbegin和rend进行反向迭代std::cout << "List1 in reverse: ";for (auto rit = list1.rbegin(); rit != list1.rend(); ++rit) {std::cout << *rit << " ";}std::cout << "\n";// 使用cbegin和cend进行const迭代std::cout << "List1: ";for (auto cit = list1.cbegin(); cit != list1.cend(); ++cit) {std::cout << *cit << " ";}std::cout << "\n";return 0;
}
  • splice: 将一个list中的元素转移到另一个list中,不进行元素的复制或移动,而是改变节点的链接。
  • remove: 删除list中所有与给定值匹配的元素。
  • remove_if: 根据给定的条件删除元素。
  • merge: 合并两个已排序的list,并清空被合并的list。
  • sort: 对list中的元素进行排序。
  • reverse: 反转list中元素的顺序。
  • swap: 交换两个list的内容。
  • resize: 调整list的大小,可以增加或减少元素数量。
  • clear: 清空list中的所有元素。
  • rbegin, rend: 提供反向迭代器,用于从list的末尾向开始进行遍历。
  • cbegin, cend: 提供常量正向迭代器,用于从list的开始到末尾的遍历,不允许修改元素。
  • crbegin, crend: 提供常量反向迭代器,用于从list的末尾到开始的遍历,不允许修改元素。

list的数据结构

STL中list是使用环状双向链表实现的。它的结点结构定义如下:

template <class T>
struct __list_node {typedef void* void_pointer;void_pointer next;void_pointer prev;T data;
};

可以看出list节点是一个双向链表,next指向下一个节点,prev指向前一个节点。

链表最后使用一个指针指向环形链表的空白节点,空白节点指向头节点,这样就形成了一个环了。

template<class T,class Alloc = alloc> //缺省使用alloc为配置器class list{  protected :  typedef __list_node<T> list_node ;  public  :  typedef list_node* link_type ;  protected :  link_type node ; //只要一个指针,便可以表示整个环状双向链表  ...};

node是指向list节点的一个指针,可以使用这个指针表示整个环状双向链表。

如果指针node指向置于尾端的一个空白节点,node就能符合stl对于前闭后开区间的要求,这样以下函数便能轻易完成。

iterator begin() { return (link_type)((*node).next); }
iterator end() { return node; }bool empty() const { return node->next == node; }size_type size() const
{size_type result = 0;distance(begin(), end(), result);//SGI里面的distance函数作用就是遍历链表return result;
}reference front() { return *begin(); }
reference back() { return *(--end()); }

list的迭代器

list是一个双向链表实现的容器,元素在内存中不需要连续存放。vector需要其元素在内存中连续存放,vector可以使用普通指针作为迭代器。

因此,list不能使用普通指针作为迭代器,因为它需要特殊的迭代器。

list提供的迭代器是双向迭代器(Bidirectional Iterators),允许前移和后移操作​。

vector插入操作可能会导致容器重新分配内存,这会使所有现有迭代器、引用和指针失效。

list删除操作,只有指向被删除元素的迭代器会失效,其他迭代器仍然有效​​。插入不会使任何的迭代器失效。

template<class T,class Ref,class Ptr>struct _list_iterator{typedef _list_iterator<T,T&,T*> iterator;typedef _list_iterator<T,T&,T*> iterator;​typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef _list_node<T>* link_type;typedef size_t size_type;typedef ptrdiff_t difference_type;link_type node;_list_iterator(link_type x):node(x){}_list_iterator(){}_list_iterator(const iterator& x):node(x.node){}bool operator==(const self& x) const {return node==x.node;}bool operator!=(const self& x) const {return node!=x.node;}reference operator*() const {return (*node).data;}reference operator->() const {return &(operator*());}      self& operator++(){node=(link_type)((*node).next);return *this;}self operator++(int){self tmp=*this;++*this;return tmp;}self& operator--(){node=(link_type)((*node).prev);return *this;}self operator--(int){self tmp=*this;--*this;return tmp;}}

list节点的构造和释放

template <class T, class Alloc = alloc>
class list {
public://...// 默认构造函数list() { empty_initialize(); }
protected:// 为结点分配内存link_type get_node() { return list_node_allocator::allocate(); }// 回收内存void put_node(link_type p) { list_node_allocator::deallocate(p); }// 构造nodelink_type create_node(const T& x) {link_type p = get_node();construct(&p->data, x);return p;}// 销毁nodevoid destroy_node(link_type p) {destroy(&p->data);put_node(p);}// 初始化void empty_initialize() {node = get_node();node->next = node;node->prev = node;}
// ...
};

默认构造函数调用empty_initialize()来初始化链表。这个初始化函数设置了一个哨兵节点(或称为头节点),使得链表的nextprev指针都指向自己,表示一个空的链表。

list操作

insert:类似双向链表的插入。

terator insert(iterator position, const T& x)
{link_type tmp = create_node(x);   // 产生一个节点// 调整双向指针,使tmp插入tmp->next = position.node;tmp->prev = position.node->prev;(link_type(position.node->prev))->next = tmp;position.node->prev = tmp;return tmp;
}

erase:类似双向链表的删除。

iterator erase(iterator position){  link_type next_node=link_type(position.node->next);  link_type prev_node=link_type(position.node->prev_nodext);  prev_node->next=next_node;  next_node->prev=prev_node;  destroy_node(position.node);  return iterator(next_node);  } 

 push_front(),push_back(),pop_front(), pop_back()在insert和erase的基础上实现。

参考:

《C++ STL 源码剖析》

https://www.cnblogs.com/runnyu/p/5992839.html

https://www.cnblogs.com/LEEYATWAH/p/11707589.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/683982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS Code添加环境变量

有时候你会发现即使添加了环境变量, 打开VS Code的命令行终端也找不到对应的环境变量。遇到这种情况可以通过给VS Code的终端独立添加对应环境变量解决: 步骤1. 找到设置 步骤2. 找到windows终端环境变量配置 3. 在此处配置然后重新打开一个终端即可 (完)

【leetcode热题100】相同的树

难度&#xff1a; 简单通过率&#xff1a; 49.0%题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目描述 给定两个二叉树&#xff0c;编写一个函数来检验它们是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的…

ZISUOJ 2022年算法基础公选课练习四(Map)

说明&#xff1a; 博主为了提早预习数据结构和C的一些知识&#xff0c;自己琢磨外加查阅资料所写的代码&#xff0c;题目来源于22年初的学院老师组织的算法基础公选课的练习。我的代码甚至思路肯定存在许多不足和错误&#xff0c;欢迎大家批评指正。 题目列表&#xff1a; 问题…

HCIA-HarmonyOS设备开发认证V2.0-轻量系统内核基础-互斥锁mux

目录 一、互斥锁基本概念二、互斥锁运行机制三、互斥锁开发流程四、互斥锁使用说明五、互斥锁接口六、代码分析&#xff08;待续...&#xff09; 一、互斥锁基本概念 互斥锁又称互斥型信号量&#xff0c;是一种特殊的二值性信号量&#xff0c;用于实现对共享资源的独占式处理。…

(力扣记录)98. 验证二叉搜索树

数据结构&#xff1a;树&#x1f332; 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(n) 代码实现&#xff1a; class Solution:def isValidBST(self, root: Optional[TreeNode]) -> bool:def dfs(root, l, r):if not root:return Trueif not l < root.val &l…

Serverless里FaaS与BaaS

目录 什么是FaaS&#xff1f; 什么是BaaS&#xff1f; 什么是FaaS&#xff1f; FaaS 即 Functions as a Service&#xff0c;函数即服务&#xff0c;是Serverless架构的一种形态&#xff0c;面向函数编程&#xff0c;基于事件驱动提供云服务之间端到端的解决方案。借助FaaS&a…

华为HCIE课堂笔记第十八章 SR技术

第十八章 SR技术 18.1 简介 SR可以通过控制器实现集中算路&#xff0c;并根据业务的不同下发不同的路径给到头端设备&#xff0c;头端设备将路径标签通过标签栈的形式压入到报文中&#xff0c;沿途的设备不需要维护路径信息&#xff0c;仅按照标签栈中的栈顶进行报文转发即可…

STM32——OLED菜单(二级菜单)

文章目录 一.补充二. 二级菜单代码 简介&#xff1a;首先在我的51 I2C里面有OLED详细讲解&#xff0c;本期代码从51OLED基础上移植过来的&#xff0c;可以先看完那篇文章&#xff0c;在看这个&#xff0c;然后按键我是用的定时器扫描不会堵塞程序,可以翻开我的文章有单独的定时…

Flutter Android开发 梳理Google Material Design颜色体系

前言 做安卓开发&#xff08;Kotlin语言&#xff09;&#xff0c;Flutter开发的人员应该都听说过谷歌一直推崇的Material Design&#xff0c;而Material Design Color是其推崇的颜色体系&#xff0c;具体来说&#xff0c;Material Design Color是一套旨在帮助设计师和开发者创…

Panalog 日志审计系统 libres_syn_delete.php 前台RCE漏洞复现

0x01 产品简介 Panalog是一款日志审计系统,方便用户统一集中监控、管理在网的海量设备。 0x02 漏洞概述 Panalog日志审计系统 libres_syn_delete.php接口处存在远程命令执行漏洞,攻击者可执行任意命令,接管服务器权限。 0x03 影响范围 version <= MARS r10p1Free 0…

vue3-使用 Vue 的多种方式

概览 我们相信在 Web 的世界里没有一种方案可以解决所有问题。正因如此&#xff0c;Vue 被设计成一个灵活的、可以渐进式集成的框架。根据使用场景的不同需要&#xff0c;相应地有多种不同的方式来使用 Vue&#xff0c;以此在技术栈复杂度、开发体验和性能表现间取得最佳平衡。…

java+springboot+vue试题库在线学习系统05umj

技术路线&#xff1a; B/S架构&#xff0c;后端springboot框架&#xff0c;前端Vue.js框架。 主要功能模块&#xff08;至少六大功能&#xff09;&#xff0c;参考任务书并拓展 &#xff08;1&#xff09;用户管理模块&#xff1a;规定不同角色的用户对系统中各个功能模块的使用…

【经验】JLINK无法(单步)调试,JLINK固件的烧写

昨天终于准备开始进行S3C6410的裸机开发&#xff0c;写好了程序&#xff0c;编译生成了.axf文件&#xff0c;一切顺利的准备利用JLINK进行在线调试了&#xff0c;突然有种成功就在前面的感觉&#xff0c;Jlink也能被电脑正常的识别&#xff0c;利用AXD进行Jlink的相关设置也很正…

安卓自定义画板

包含功能&#xff1a; 包含 获取当前画板的截图、设置画笔样式、获取画笔样式、设置画笔宽度、获取画笔宽度、设置画笔颜色、获取画笔颜色、加载图片、获取图片位图对象、设置图片位图对象&#xff0c;并在画布上绘制图片、撤销上一步操作、重做上一步撤销的操作、清空所有绘图…

用机器学习方法重构期货商品板块

用机器学习方法重构期货商品板块 阿岛格 参考专栏:低门槛搭建个人量化平台 https://www.zhihu.com/column/c_1441014235068944386 摘 要 金融市场商品期货的板块分类,通常根据不同交易所、监管机构和证券商标准,按照期货标的属性、或产业链关系等进行分类,各自分类略有差…

ROS-Ubuntu20.04环境安装

1.系统和ROS版本 操作系统&#xff1a;Ubuntu20.04 ROS版本&#xff1a;ROS noetic 2.安装步骤 1.配置ROS软件源 sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list 2.配置密钥…

Dirty PageTable

前言 Dirty PageTable 是一种针对堆相关漏洞的利用手法&#xff0c;主要就是针对 PTE 进行攻击。 参考文章&#xff1a; Dirty Pagetable: A Novel Exploitation Technique To Rule Linux Kernel – 该利用方式提出原文 上述文章已经讲的非常清楚了&#xff0c;就是实操写 e…

海伦公式求三角形面积

海伦公式&#xff0c;又译作希伦公式、海龙公式、希罗公式、海伦-秦九韶公式&#xff0c;是一种用于计算三角形面积的公式。其表达式为&#xff1a;S√p(p-a)(p-b)(p-c)&#xff0c;其中p是半周长&#xff0c;即p(abc)/2。这个公式的特点是形式漂亮&#xff0c;便于记忆。 相传…

挑战杯 python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…

【Java基础题型】判断是否是回文数

需求&#xff1a;如果给你一个正数x。 如果x是一个回文整数&#xff0c;打印true&#xff0c;否则&#xff0c;返回false 解释&#xff1a; 回文数是指正序(从左到右)和从倒序(从右到左)都是一样的整数数字。 eg.121是回文数&#xff0c;123不是&#xff0c;2112是回文数&…