当前位置: 首页 > news >正文

C++-->stl: list的使用

前言list的认识

list是可以在固定时间(O(1))内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向(当然有一个哨兵位 就是说头节点)
其前一个元素和后一个元素。
3. listforward_list非常相似:最主要的不同在于forward_list是单链表,只能向前迭代,已让其更简单高(list是doubly list的接口 forward_list是单链表的接口)
效。
4. 与其他的序列式容器相比(arrayvectordeque)list通常在任意位置进行插入、移除元素的执行效率 更好。
5. 与其他序列式容器相比,listforward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间  (需要创建一个结点去遍历,比随机访问效率低)
   开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的list来说这不合适 可能是一个重要的因素

1 list的构造
常用的构造函数

default (1)

默认构造)

explicit list (const allocator_type& alloc = allocator_type());

      fill (2)

 n个val值填充

explicit list (size_type n, const value_type& val = value_type(),const allocator_type& alloc = allocator_type());

range (3)

   迭代器构造

template <class InputIterator>list (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());

copy (4)

拷贝构造

list (const list& x);
参考代码 : 
   
void print_list(list<int>& list1)
{list<int>::iterator it = list1.begin();while (it != list1.end()){cout << *it;it++;}cout << endl;}
void construct_test()
{list<int>list_1;// 空构造list<int>list_2(20,0);// n  vallist<int>::iterator it = list_2.begin();  // 迭代器构造 list<int> th(list_2.begin(),list_2.end());// 不支持的写法 list<int> th(list_2.begin(),list_2.begin()+4);// 因为list的迭代器不支持随机访问哦 其实本质上是因为只给迭代器封装了++的操作 int arr[] = {1,2,3,4,5,6};list<int>four(arr,arr+4);// 这也是迭代器构造 数组肯定是可以通过下标 随机访问啦 // 拷贝构造//list<int> five = four;list<int> five(four);print_list(five);}

2. list的迭代器 

    list的图解 

迭代器的理解:

  
  这个迭代器的内部封装可以大致这么理解:
    肯定是对node的操作,封装node的移动,有++,--以及!=   判断俩个迭代器是否相等就这样就很常见,封装的目的很简单,就是为了统一容器的操作哦!。
    后期博客我会更新其中的模拟实现这是很有意思的:
   内部是没有封装+某个数的 
   所以之前例子中指出 像这样的 list<int>::iterator(it,it+3);  是不被允许的哦!
总之因为list的底层容器是双向链表,每个节点地址之间是不连续的,所以我们为了统一容器操作就封装迭代器了。
迭代器使用:代码实例:
void iterator_test() {int arr[] = { 1,2,3,4,5,6 };list<int>four(arr, arr + 5);// 用迭代器遍历four这个链表list<int>::iterator it = four.begin();// 正向迭代器list<int>::reverse_iterator rit = four.rbegin();// 反向迭代器while (it != four.end()){cout << *it;it++;}cout << endl;while (rit != four.rend()){cout << *rit;rit++;}cout << endl;}
输出:12345   
           54321

doubly list的图解

   这里只标出了 node之间指针的关系,这里值得注意的就是如何实现双向循环的,就是创建一个头节点,头节点作用就是用来很方便的实现增删查改(减少判空这个策略数据结构中可以多了解理解) 总之就是让头节点的pre指向尾节点,尾节点的next指向头节点。 总之头节点是不存放有效数据的! 所以下面我说说迭代器遍历的问题!

 list迭代器遍历的理解: 

      显然 list<T>iterator:: begin 指向的是头节点的下一个位置,node结构体中总是存放的是头节点,所以需要遍历的时候需要总是从头节点开始一一遍历,而不是随机访问。 
    判断到尾部的方法有很多一个是根据size,以及cur节点的遍历到了头节点了。

3. list element access(元素获取)

     list的获取常用的就是一个是front  和 back  双向链表根据头节点实现起来很方便的。

     

3.1 reference front()  和reference back的使用
        这个list的front的成员函数,简单来说就是返回一个头节点的元素引用。 
这里的referrence其实是一个typedef,这个在库里面实现是很常见的  可以这样理解:
typedef reference T;
  back同理如上。
   
// list::front
#include <iostream>
#include <list>int main ()
{std::list<int> mylist;mylist.push_back(77);mylist.push_back(22);// now front equals 77, and back 22mylist.front() -= mylist.back();std::cout << "mylist.front() is now " << mylist.front() << '\n';return 0;
}

输出: 55

4. list modified 元素修改

    list常用的修改方面的有:  头插,头删,尾删,尾插,还有指定位置删除,和指定位置插入,还有指定尾插删除, 以及swap (经常被用于去写构造函数的还有拷贝构造)

4.1 push_front 和pop_front

实现:
// list::push_front
#include <iostream>
#include <list>int main ()
{std::list<int> mylist (2,100);         // two ints with a value of 100mylist.push_front (200);mylist.push_front (300);std::cout << "mylist contains:";for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

实现:
// list::pop_front
#include <iostream>
#include <list>int main ()
{std::list<int> mylist;mylist.push_back (100);mylist.push_back (200);mylist.push_back (300);std::cout << "Popping out the elements in mylist:";while (!mylist.empty()){std::cout << ' ' << mylist.front();mylist.pop_front();}std::cout << "\nFinal size of mylist is " << mylist.size() << '\n';return 0;
}

4.2 push_back和pop_front 

    尾插和尾删 返回值都是void注意哦
  
// list::push_back
#include <iostream>
#include <list>int main ()
{std::list<int> mylist;int myint;std::cout << "Please enter some integers (enter 0 to end):\n";do {std::cin >> myint;mylist.push_back (myint);} while (myint);std::cout << "mylist stores " << mylist.size() << " numbers.\n";return 0;
}

 

// list::pop_back
#include <iostream>
#include <list>int main ()
{std::list<int> mylist;int sum (0);mylist.push_back (100);mylist.push_back (200);mylist.push_back (300);while (!mylist.empty()){sum+=mylist.back();mylist.pop_back();}std::cout << "The elements of mylist summed " << sum << '\n';return 0;
}

4.3 insert

  在指定位置(用迭代器哦) 插入一个元素,
     插入n个val 在指定位置
  在指定位置插入一个范围迭代器区间的元素

void insert_test() {int arr[] = { 1,2,3,4,5 };//    1  2  3  4  5int arr1[] = { 11,12,13,14,15 };//    11  12  13  14  15vector<int>v1(arr,arr+5);list<int> mylist(arr1,arr1+5);     //     !list<int>::iterator it = mylist.begin();it++;mylist.insert(it,10);// 迭代器可能存在失效的问题 所以这里一定要给it重赋值   print_list(mylist);// n valit = mylist.begin();it++;mylist.insert(it, 10,1);print_list(mylist);//  范围插入it = mylist.begin();it++;mylist.insert(it, v1.begin()+2, v1.end());print_list(mylist);}
输出:11 10 12 13 14 15
11 1 1 1 1 1 1 1 1 1 1 10 12 13 14 15
11 3 4 5 1 1 1 1 1 1 1 1 1 1 10 12 13 14 15

4.4 erase 删除

 传递的参数是list的迭代器,指定位置删除和指定的迭代器范围区间的元素删除。

std:: iterator& advance(iterator,len) 这是库里的移动迭代器的函数

// erasing from list
#include <iostream>
#include <list>int main ()
{std::list<int> mylist;std::list<int>::iterator it1,it2;// set some values:for (int i=1; i<10; ++i) mylist.push_back(i*10);// 10 20 30 40 50 60 70 80 90it1 = it2 = mylist.begin(); // ^^advance (it2,6);            // ^                 ^++it1;                      //    ^              ^it1 = mylist.erase (it1);   // 10 30 40 50 60 70 80 90//    ^           ^it2 = mylist.erase (it2);   // 10 30 40 50 60 80 90//    ^           ^++it1;                      //       ^        ^--it2;                      //       ^     ^mylist.erase (it1,it2);     // 10 30 60 80 90//        ^std::cout << "mylist contains:";for (it1=mylist.begin(); it1!=mylist.end(); ++it1)std::cout << ' ' << *it1;std::cout << '\n';return 0;
}

5. 迭代器失效问题

   我们之前说过迭代器的实现可以理解为一个封装了node的移动和判断的类。  这里的数据存放是node,所以本质上还是用node*指向了一个节点,所以在list中只要该节点不删除,这个节点依然存在。 
  在list中插入不会导致迭代器失效,因为这个节点并没有被销毁(vector中的迭代器失效是因为他们的内存是连续的,当扩容的时候可能导致旧内存被销数据被移动到新内存)但是list的底层是双向循环链表,内存之间都是用指针(地址)连接起来的,不用在乎是否连续,你不主动销毁内存是不会被销毁的。
   所以只有当删除的时候才会被销毁。

谈谈erase和insert的返回值

   erase:
iterator erase (iterator position);
iterator erase (iterator first, iterator last); 

insert:

single element (1)
iterator insert (iterator position, const value_type& val);
fill (2)
void insert (iterator position, size_type n, const value_type& val);
range (3)
template <class InputIterator>void insert (iterator position, InputIterator first, InputIterator last);
insert:大体上分为两,一种是插入一个元素,一个是插入多个元素。
返回值:简单理解就是返回插入元素后的下一个位置的元素
erase则是返回删除元素的下一个位置
处理迭代器失效: 就是重新赋值给迭代器:
错误实例 没有重新赋值 
修正: 
   代码: 
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时,必须先给//其赋值it =l.erase(it);++it;}
}

http://www.dtcms.com/a/320546.html

相关文章:

  • 为什么输入 URL 后会显示页面?HTTP 协议的 “幕后操作”
  • docker缓存目录转移设置和生效过程
  • 稿定科技:多云架构下的 AI 存储挑战与 JuiceFS 实践
  • 负氧离子监测站:守护清新空气的科技卫士
  • 从零掌握 Java AWT:原理、实战与性能优化
  • 用JOIN替代子查询的查询性能优化
  • 《前端60问:从设备判断到性能优化全解》
  • 高校合作 | 世冠科技联合普华、北邮项目入选教育部第二批工程案例
  • Emacs 折腾日记(二十九)—— 打造C++ IDE
  • 弱电+机房+设备+运维资料合集方案(Word+PPT)
  • 天翼云与飞轮科技达成战略合作,共筑云数融合新生态
  • 深入解析基于Zookeeper分布式锁在高并发场景下的性能优化实践指南
  • SQL聚合函数:SUM与COUNT的区别
  • 解锁Java开发新姿势:飞算JavaAI深度探秘 #飞算JavaAl炫技赛 #Java开发
  • 力扣-53.最大子数组和
  • Java基础知识总结
  • 文件管理从基础到高级:文件描述符、超大文件切片重组与快速删除实战
  • Android 的CameraX的使用(配置,预览,拍照,图像分析,录视频)
  • Harbor 企业级实战:单机快速上手 × 高可用架构搭建 × HTTPS安全加固
  • 音视频直播全链路技术手册:核心术语与实战应用解析
  • Flink的窗口
  • LangChain4j终极指南:Spring Boot构建企业级Agent框架
  • 双目标定中旋转矩阵参数应用及旋转角度计算(聚焦坐标系平行)
  • 三方相机问题分析七:【datespace导致GPU异常】facebook 黑块和Instagram花图问题
  • Linux Shell:Nano 编辑器备忘
  • 以下是使用这款ePub编辑器将指定章节转换为TXT文本文档的操作方法
  • (数据结构)链表
  • Android 安全编程:Kotlin 如何从语言层保障安全性
  • Kotlin反射
  • HarmonyOS SDK助力讯飞听见App能力建设