List

List接口使用

  1. List:双向带头循环的链表,不支持随机访问,排序就是一个大问题
    当大量的插入数据的时候就体现出了优势。

在任意位置以O(1)的时间复杂度插入数据.

  1. 只有一种遍历方式就是迭代器,因为他的物理结构是不连续的无法用下标的方式进行访问
list<int>::iterator it=lt.begin();
while(it!=lt.end())
{cout<<*it<<" ";++it;
}
cout<<endl;
  1. lt.sort();自身携带的排序方式,但是效率不太高。

  2. lt.unique();去重数据,先进行排序才能够去除干净。

  3. lt.splice();接合,将链表的节点直接转移到另一个里面去.

#include<iostream>
#include<list>
using namespace std;
int main()
{//list<int> l1;//l1.push_back(1);//l1.push_back(5);//l1.push_back(3);//l1.push_back(4);//l1.push_back(2);//l1.push_back(2);//l1.push_back(2);//l1.push_back(2);//l1.sort();//l1.unique();//先排序再去重效率更高//list<int>::iterator it = l1.begin();//while (it != l1.end())//{// cout << *it << " ";// ++it;//}//cout << endl;list<int> l1;list<int> l2;for (int i = 1; i <= 4; i++){l1.push_back(i);l2.push_back(i * 10);}auto it = l1.begin();++it;//将l2拼接到l1的指定位置处l1.splice(it,l2);l1.splice(it,l2,l2.begin(),l2.end());//advance 让it指向指定下标位置的数,必须先从头开始it = l1.begin();advance(it,2);//相当于将指定部分长度元素组,头插l1.splice(l1.begin(),l1,it,l1.end());list<int>::iterator it1 = l1.begin();while (it1 != l1.end()){cout << *it1 << " ";++it1;}cout << endl;return 0;
}

list的模拟实现

迭代器

自定义类型进行封装节点指针,自定义类型的运算符重载实现++,和operator*
end()是最后一个数据的下一个位置,就是头结点
迭代器不只是原生指针有可能是。

类型的意义
链表节点的原生指针和一个迭代器对象,他们占用的空间时一样大的,都是4byte,
并且存的值也是一样的。但是对他们使用运算符的意义和结果都是不一样的。

void f()
{Node*pnode=_head->next;iterator it=_head->next;*pnode;*it;
}

迭代器的拷贝构造和赋值重载以及析构函数都不需要我们自己实现,默认生成的就行。因为,迭代器是借助节点的指针访问和修改链表。节点属于链表不属于迭代器,所以他不用管释放的过程。默认生成的拷贝就是浅拷贝足以满足拷贝构造和赋值的需求,两个指针指向同一个迭代器同一个位置.

通过自己模拟实现迭代器的功能,使用迭代器去访问和修改链表的相关函数。

const迭代器

普通迭代器可读可写,const迭代器只能读不能修改.就是实现一个const iterator让容器的内容不可修改.这是两个迭代器.

所以要么实现一个不能修改的迭代器一般适应容器是const的,对于const类型和普通类型本身需要声明两个类的迭代器,除了类型名和返回值不同其他都相同,但是为了避免代码的冗余和重复.

可以通过控制模板参数不同的返回值来区别两个类的迭代器。加了一个Ref
这样返回值是const类型就去调用const_iterator的begin和end,普通类型就去调用普通类型的内个。

通过模板参数实现代码的复用,避免了代码的冗余。

如果迭代器指针指向的是一个结构,那我们还是要访问他本身的成员变量。所以要重载一个 operator->
使用场景:日期类。迭代器像Date*指针一样使用,结构体里面用->访问成员变量it->_year;

  • 使用场景(1->2)
void test2(){list<Date> lt;lt.push_back(Date(2022, 1, 1));lt.push_back(Date(2022, 2, 2));lt.push_back(Date(2022,3,3));list<Date>::iterator it = lt.begin();while (it != lt.end()){//1. std::cout << (*it)._year << "." << (*it)._month << "." << (*it)._day << std::endl;//2. it->:Datestd::cout << it->_year<<"."<< it->_month << "."<< it->_day<< std::endl;++it;}std::cout << std::endl;}

it.operator->(),返回来是Date*``,Date*访问成员又是一个->所以本来应该是it->->year,这样运算符的可读性变差。编译器进行优化为一个->,所有类型想要重载都会是这样的。

//迭代器中重载这样的函数
T *operator->()
{return &_node->_data;
}

如果是const迭代器,所以类似于Ref的添加一个模板参数Ptr.

增删查改

stringvector是连续的物理空间,模拟指针的行为,像指针一样去访问容器,原生指针就是天然的迭代器。支持随机访问,但是增容可能造成浪费空间,插入删除要挪动数据.

list按需申请和释放空间,在任意位置支持O(1)的插入删除。所以vector和list是互补的两个数据结构。

iterator 类去封装节点指针,重载运算符,让他像指针一样。STL的所有容器都不能保证线程安全。
泛型,复用,封装。

insert()

在既定pos的前一个位置进行插入新的节点,list 的迭代器,insert之后不会发生失效。vector会野指针(异地扩容)和意义改变(数据移动覆盖导致)

插入之后,STL里面的会返回插入节点的迭代器指针。

erase()

不能将头结点删除,断言处理.返回删除之后下一个节点.

拷贝构造的实现:深浅拷贝的问题

push_back()的前提是这个链表被初始化了,就需要他已经存在哨兵位的头节点,所以在调用之前要创建一个头结点,并且自己指向自己。

     list(const list<int>& lt){_head = new Node();_head->_next = _head;_head->_prev = _head;for (auto e : lt){push_back(e);}}

赋值构造

     list& operator=(const list<int>& lt){if (this != &lt){clear();_head = new Node();_head->_next = _head;_head->_prev = _head;for (auto e : lt){push_back(e);}}return *this;}
//升级版本
template<class InputIterator >list(InputIterator first, InputIterator last){_head = new Node();_head->_next = _head;_head->_prev = _head;while (first != last){push_back(*first);++first;}};list<T>(const list<T>& lt){//避免交换的时候_head为随机值_head = new Node();_head->_next = _head;_head->_prev = _head;list<T>tmp(lt.begin(),lt.end());std::swap(_head, tmp._head);}list<T>& operator=(list<T> lt){std::swap(_head, lt._head);return *this;}

非法间接寻址

当迭代器区间初始化list(InputIterator first, InputIterator last)list(size_t n, const T& val = T())同时存在时,

void test4()
{list<Date>lt1(5,Date(2022,1,1));//类型不同,走得list()list<int>lt2(5,1);//两个都是int,走得迭代器区间那个,造成间接非法寻址//匹配函数的时候,有现成的是不会去推演模板的
}
  • 可以将size_t重载一个int类型就可以解决因为参数类型不同造成的匹配函数错误.

反向迭代器

本身包含正向迭代器,对于正向迭代器的一种封装,重载++--的方向。区别就是++和–的方向是相反的。
正向迭代器的开始就是反向迭代器的结束。

operator*取前一个位置主要就是为了让反向迭代器开始和结束跟正向迭代器对称。

reference operator* const()
{Iterator tmp=current;return *--tmp;
}

所以以后别的不是链表的反向迭代器都可以像这个一样进行复用。
iterator 是哪个容器的迭代器,reverse_iterator就可以适配哪个容器的反向迭代器.

 template <class Iterator, class Ref, class Ptr>class reverse_iterator{typedef reverse_iterator<Iterator, Ref, Ptr> self;public:reverse_iterator(Iterator it):_it(it){}Ref operator*(){//return *_it;Iterator prev = _it;return *--prev;}Ptr operator->(){return &operator*();}self& operator++(){--_it;return *this;}self& operator--(){++_it;return *this;}bool operator!= (const self & rit) const{return _it != rit._it;}private:Iterator _it;};

删除节点后,只有指向当前节点的迭代器失效了,其前后的迭代器仍然有效,
因为底层为不连续空间,只有被删除的 节点才会失效
vector由于在头部插入数据效率很低,所以没有提供push_front方法,但是如果需要有insert可以使用.

List-反向迭代器相关推荐

  1. Vector反向迭代器使用

    反向迭代器 1 反向迭代器其实没什么特殊的,他只是在遍历的方向上和普通迭代器不通而已:每一个容器里面都有Iterator(迭代器),可以从容器的begin位置到end-1位置,通过++来遍历.同样也有 ...

  2. boost::stl_interfaces模块实现反向迭代器的测试程序

    boost::stl_interfaces模块实现反向迭代器的测试程序 实现功能 C++实现代码 实现功能 boost::stl_interfaces模块实现反向迭代器的测试程序 C++实现代码 #i ...

  3. 迭代器和反向迭代器,常量迭代器和非常量迭代器

    迭代器的类型共有4种:<T>::Iiterator,<T>::const_iterator,<T>::reverse_iterator,<T>::con ...

  4. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

  5. c++STL的反向迭代器

    反向迭代器 反向迭代器是一种反向遍历容器的迭代器.也就是,从最后一个元素到第一个元素遍历容器.反向迭代器将自增(和自减)的含义反过来了:对于反向迭代 器,++ 运算将访问前一个元素,而 – 运算则访问 ...

  6. 插入迭代器、流迭代器、反向迭代器、移动迭代器

    文章目录 前言 插入迭代器 inserter front_inserter back_inserter iostream迭代器 istream_iterator 读取输入流 istream_itera ...

  7. std::string中的反向迭代器rbegin()和rend()

    在std::string中,有个接口是rbegin()和rend(),分别表示string字符串的倒数第一个字符和正数第一个字符: rbegin():表示string字符串的倒数第一个字符 rend( ...

  8. python反向迭代器_Python中对象迭代与反迭代的技巧总结

    一.如何实现可迭代对象和迭代器对象? 实际案例 某软件要求从网络抓取各个城市气味信息,并其次显示: 北京: 15 ~ 20 天津: 17 ~ 22 长春: 12 ~ 18 ...... 如果一次抓取所 ...

  9. Leetcode 58 之反向迭代器的使用

    题目: Given a string s consists of upper/lower-case alphabets and empty space characters' ', return th ...

  10. 【C++】迭代器、反向迭代器详解

    参考: http://c.biancheng.net/view/338.html https://blog.csdn.net/kjing/article/details/6936325 https:/ ...

最新文章

  1. TCP_Wrappers 基于TCP的安全控制
  2. [Web 前端] inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移
  3. poj 1192(简单树形dp)
  4. PowerDesigner16导出Sql修复
  5. matlab 图像的色彩强度,图像色彩增强的问题,,,小白给跪,
  6. GridView 添加分害线
  7. myeclipse运行java项目_myeclipse运行自己从前的或其他人的javaweb项目
  8. 古墓:黑夜中不断的断龙石敲击声
  9. 利用k-means算法实现图像自动色彩量化
  10. Java 8.9 游戏:井字游戏(C++Java)
  11. java数字金额大写金额_Java实现 将数字金额转为大写中文金额
  12. linux dnf配置文件,RedHat8.1配置本地dnf源
  13. opencv实现摄像头的实时人脸识别
  14. setoolikt制作钓鱼网站
  15. acwing 1212. 地宫取宝(蓝桥杯)
  16. protoc导出时遇到protoc-gen-go unable to determine Go import path解决方法
  17. Java多线程学习(吐血超详细总结)转自博主林炳文Evankaka
  18. html图片文字下方,css图片下边怎么加字
  19. h5 video 移动端 视频添加第一帧作为播放前图片
  20. 专知原创和整理了一些中英文机器学习从入门到精通的资料,和大家分享一下

热门文章

  1. 论文笔记《Learning Deep Correspondence through Prior and Posterior Feature Constancy》
  2. 让地球的实时美丽照片显示在你的Mac桌面上-即刻地球 mac中文版
  3. 4.GraphPad常见统计分析方法
  4. Nginx-域名跳转到另外一个域名
  5. 52 Movies Every Tech Geek Must See
  6. 【Unity3D 教程系列第 19 篇】Unity 中根据长方体模型的尺寸添加碰撞盒 BoxCollider
  7. 【BMI指数计算器V2.0】项目实战
  8. 为了分析最近热点电影的观众爱好取向,爬取《镇魂》微博评论数据
  9. 夺命雷公狗---node.js---2node.js中的npm的常用命令
  10. PPT图片莫名其妙变空白或者红叉