Lesson10---list
Lesson10—list
第10章 c++的list的使用和实现
文章目录
- Lesson10---list
- 前言
- 一、list的初始化
- 二、list的遍历
- 1.迭代器
- 2.范围for
- 三、list常用的内置函数
- 1.sort(慎用)
- 2.unique
- 3.reverse
- 4.merge
- 5.splice
- 四、模拟实现
- 1.基本框架
- 2.构造函数
- 3.push_back
- 4. 遍历
- 5.const迭代器
- 6.代码
- 7.const迭代器改进
- 8.insert
- 9.erase
- 10. pop_back
- 11. push_front
- 12.pop_front
- 13.clear
- 14.析构函数
- 15.拷贝构造
- 16.赋值
- 17.initializer
- 五.完整代码
- 总结
前言
这篇博客写了怎么使用list和怎么实现
list和前面的string 和vector 的有很多重复的就不过多赘述
一、list的初始化
vector的底层是数组,list的底层是结构体,所以list不能用下标的方式去访问,因为这样会让效率变的特别低
可以直接用花括号去初始化这样就不要一个个尾插,vector和list都可以
二、list的遍历
1.迭代器
vector的底层是数组,在内存上是连续的但是链表不是,但这里链表依旧可以使用迭代器来遍历,非常的强大
既然可以用迭代器去访问一个在内存上不连续的list那能不能给这个链表用sort排序呢?
答案是不能,因为这样排序效率特别低,如果想要去排序链表,list提供了sort函数
2.范围for
有很多和vector重复了就不重复写了感兴趣的可以看我的vector篇
三、list常用的内置函数
1.sort(慎用)
默认是升序加上仿函数是降序
list的排序底层用的不是快排用的是归并排序,如果数据很多又要排序就不要用list用vector
list排序时间是vector的三倍左右,而且特别稳定基本都是三倍左右,虽然归并排序和快排都是nlogn但是list排序还是罗逊vector
甚至把list里面的数据拷贝给vector让vector用快排排序,把排序好的数据在拷贝回来这样会都比list的sort的归并排序快简直拉跨
2.unique
unique的作用是去重但数据必须是排序以后或者连续的
不排序或者不连续就会这样去不干净
3.reverse
逆置这个链表,比较简单
4.merge
合并链表,这里必须是要有序的
5.splice
这个函数差不多就是剪切的意思,第一个参数要迭代器,第二个参数是链表
从迭代器的位置插入一整个链表
还可以这样用
四、模拟实现
模板不建议声明和定义分开会有各种问题,建议直接把定义写在.h文件里面
1.基本框架
#pragma once
#include<iostream>
using namespace std;
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prve;T _data;
};template<class T>
class my_list
{
public:typedef ListNode<T> Node;
private:Node* _head;
};
先把基本的框架写好来
2.构造函数
3.push_back
这里可以画个草图理解,要尾插就要先找尾巴
void push_back(const T& x)
{Node* newnode = new Node(x);Node* tail = _head->_prve;tail->_next = newnode;newnode->_prve = tail;newnode->_next = _head;_head->_prve = newnode;
}
运行以后会这个错误
编译器给的是这个错误,这是因为,new Node 会去调用 node默认构造函数但是这里没有写
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prve;T _data;ListNode(const T& data = T()):_next(nullptr),_prve(nullptr),_data(data){}
};
4. 遍历
链表在逻辑上是连在一起的但是它在物理上就不一定是连续的了是所用它不能想vector一样的用++去遍历vector底层是数组
这里我采用迭代器的方式去遍历,因为指针++需要像数组那样在物理上连续才可以所以这里采用封装然后运算符重载去实现
class ListIterator
{
public:typedef ListNode<T> Node;typedef ListIterator<T> self;Node* _node;ListIterator(Node* node):_node(node){}self& operator++( ){_node = _node->_next;return *this;}T& operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}
};
这样就可以遍历了,也支持范围for
5.const迭代器
如果有人这样去访问迭代器就会把回来的值改变不安全,有时候还会在不经意间改变原来的值
这里还需要重载一个const迭代器,只能去访问但是不能修改里面的值
template<class T>
class ListConstIterator{
public:typedef ListNode<T> Node;typedef ListConstIterator<T> self;ListConstIterator(Node* node):_node(node){}Node* _node;self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prve;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}const T& operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}bool operator ==(const self& it){return _node == it._node;}
};
这里只需要复制一份原来的迭代器改下名字就行,然后重载一下
然后加上const就可以了然后再去my_list里面加上就行
加上const迭代器的begin和end
这里就不让改了
6.代码
#pragma once
#include<iostream>
using namespace std;
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prve;T _data;ListNode(const T& data = T()):_next(nullptr),_prve(nullptr),_data(data){}
};
template<class T>
class ListIterator{
public:typedef ListNode<T> Node;typedef ListIterator<T> self;ListIterator(Node* node):_node(node){}Node* _node;self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prve;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}T& operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}bool operator ==(const self& it){return _node == it._node;}
};
template<class T>
class ListConstIterator{
public:typedef ListNode<T> Node;typedef ListConstIterator<T> self;ListConstIterator(Node* node):_node(node){}Node* _node;self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prve;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}const T& operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}bool operator ==(const self& it){return _node == it._node;}
};template<class T>
class my_list
{
public:typedef ListNode<T> Node;typedef ListIterator<T> iterator;typedef ListConstIterator<T> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin()const {return const_iterator(_head->_next);}const_iterator end()const {return const_iterator(_head);}my_list(){_head = new Node;_head->_next = _head;_head->_prve = _head;}void push_back(const T& x){Node* newnode = new Node(x);Node* tail = _head->_prve;tail->_next = newnode;newnode->_prve = tail;newnode->_next = _head;_head->_prve = newnode;}private:Node* _head;
};
7.const迭代器改进
上面const迭代器有一个问题,就是只要解引用那一点点不一样甚至只是返回值加了const代码就边长了那么多这里还可以在优化一下
#pragma once
#include<iostream>
using namespace std;
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prve;T _data;ListNode(const T& data = T()):_next(nullptr), _prve(nullptr), _data(data){}
};
template<class T,class Ref>
class ListIterator{
public:typedef ListNode<T> Node;typedef ListIterator<T,Ref> self;ListIterator(Node* node):_node(node){}Node* _node;self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prve;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}Ref operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}bool operator ==(const self& it){return _node == it._node;}
};
//template<class T>
//class ListConstIterator
//
//{
//public:
//
// typedef ListNode<T> Node;
// typedef ListConstIterator<T> self;
// ListConstIterator(Node* node)
// :_node(node)
// {
//
// }
// Node* _node;
// self& operator++()
// {
// _node = _node->_next;
// return *this;
// }
// self& operator--()
// {
// _node = _node->_prve;
// return *this;
// }
// self operator++(int)
// {
// self tmp(*this);
// _node = _node->_next;
// return tmp;
// }
// self operator--(int)
// {
// self tmp(*this);
// _node = _node->_prve;
// return tmp;
// }
// const T& operator*()
// {
// return _node->_data;
// }
// bool operator !=(const self& it)
// {
// return _node != it._node;
// }
// bool operator ==(const self& it)
// {
// return _node == it._node;
// }
//};template<class T>
class my_list
{
public:typedef ListNode<T> Node;typedef ListIterator<T,T&> iterator;typedef ListIterator<T,const T&> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin()const{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}my_list(){_head = new Node;_head->_next = _head;_head->_prve = _head;}void push_back(const T& x){Node* newnode = new Node(x);Node* tail = _head->_prve;tail->_next = newnode;newnode->_prve = tail;newnode->_next = _head;_head->_prve = newnode;}private:Node* _head;
};
8.insert
可以画个草图方便理解
iterator insert(iterator pos ,const T& x)
{Node* newnode = new Node(x);Node* cur = pos._node;newnode->_prve = cur->_prve;cur->_prve->_next = newnode;newnode->_next = cur;cur->_prve = newnode;return iterator(newnode);
}
9.erase
iterator erase(iterator pos)
{Node* cur = pos._node;Node* prve = cur->_prve;Node* next = cur->_next;prve->_next = next;next->_prve = prve;delete cur;return iterator(next);
}
10. pop_back
void pop_back()
{erase(--end());
}
11. push_front
void push_front(const T& x)
{insert(begin(), x);
}
12.pop_front
void pop_front()
{erase(begin());
}
13.clear
void clear()
{auto it = begin();while (it !=end()){it=erase(it);}
}
14.析构函数
~my_list()
{clear();delete _head;_head = nullptr;
}
15.拷贝构造
my_list(const my_list<T>& lt)
{_head = new Node;_head->_next = _head;_head->_prve = _head;for (const auto& e : lt){push_back(e);}
}
16.赋值
my_list<T>& operator = (my_list<T> lt)
{swap(lt._head, _head);return *this;
}
17.initializer
my_list(initializer_list<T> il)
{_head = new Node;_head->_next = _head;_head->_prve = _head;for (auto e : il){push_back(e);}
}
五.完整代码
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prve;T _data;ListNode(const T& data = T()):_next(nullptr), _prve(nullptr), _data(data){}
};
template<class T, class Ref>
class ListIterator{
public:typedef ListNode<T> Node;typedef ListIterator<T, Ref> self;ListIterator(Node* node):_node(node){}Node* _node;self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prve;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}Ref operator*(){return _node->_data;}bool operator !=(const self& it){return _node != it._node;}bool operator ==(const self& it){return _node == it._node;}
};
//template<class T>
//class ListConstIterator
//
//{
//public:
//
// typedef ListNode<T> Node;
// typedef ListConstIterator<T> self;
// ListConstIterator(Node* node)
// :_node(node)
// {
//
// }
// Node* _node;
// self& operator++()
// {
// _node = _node->_next;
// return *this;
// }
// self& operator--()
// {
// _node = _node->_prve;
// return *this;
// }
// self operator++(int)
// {
// self tmp(*this);
// _node = _node->_next;
// return tmp;
// }
// self operator--(int)
// {
// self tmp(*this);
// _node = _node->_prve;
// return tmp;
// }
// const T& operator*()
// {
// return _node->_data;
// }
// bool operator !=(const self& it)
// {
// return _node != it._node;
// }
// bool operator ==(const self& it)
// {
// return _node == it._node;
// }
//};template<class T>
class my_list
{
public:typedef ListNode<T> Node;typedef ListIterator<T, T&> iterator;typedef ListIterator<T, const T&> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin()const{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}void empty(){_head = new Node;_head->_next = _head;_head->_prve = _head;}my_list(){empty();}//lt2(lt1)my_list(initializer_list<T> il){empty();for (auto e : il){push_back(e);}}my_list(const my_list<T>& lt){empty();for (const auto& e : lt){push_back(e);}}~my_list(){clear();delete _head;_head = nullptr;}//lt3 = lt1my_list<T>& operator = (my_list<T> lt){swap(lt._head, _head);return *this;}void push_back(const T& x){/*Node* newnode = new Node(x);Node* tail = _head->_prve;tail->_next = newnode;newnode->_prve = tail;newnode->_next = _head;_head->_prve = newnode;*/insert(end(), x);}iterator insert(iterator pos ,const T& x){Node* newnode = new Node(x);Node* cur = pos._node;newnode->_prve = cur->_prve;cur->_prve->_next = newnode;newnode->_next = cur;cur->_prve = newnode;return iterator(newnode);}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prve = cur->_prve;Node* next = cur->_next;prve->_next = next;next->_prve = prve;delete cur;return iterator(next);}void pop_back(){erase(--end());}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void clear(){auto it = begin();while (it !=end()){it=erase(it);}}
private:Node* _head;
};
总结
例如:以上就是要讲的内容,本文仅仅简单介绍了list的使用和简单的模拟实现
相关文章:

Lesson10---list
Lesson10—list 第10章 c的list的使用和实现 文章目录 Lesson10---list前言一、list的初始化二、list的遍历1.迭代器2.范围for 三、list常用的内置函数1.sort(慎用)2.unique3.reverse4.merge5.splice 四、模拟实现1.基本框架2.构造函数3.push_back4. 遍…...

ASP.NET Core 8.0 中使用 Hangfire 调度 API
在这篇博文中,我们将引导您完成将 Hangfire 集成到 ASP.NET Core NET Core 项目中以安排 API 每天运行的步骤。Hangfire 是一个功能强大的库,可简化 .NET 应用程序中的后台作业处理,使其成为调度任务的绝佳选择。继续阅读以了解如何设置 Hang…...
查看linux的版本
在 Linux 系统中,有多种方法可以查看当前系统的版本信息。以下是一些常用的方法: 1. 使用 uname 命令 uname 命令可以显示系统的内核版本和其他相关信息。 uname -a这个命令会输出类似如下的信息: Linux hostname 5.4.0-88-generic #99-U…...

Mysql补充
单例 双重检查锁 class Singleton {private static volatile Singleton instance ;private Singleton() {}public static Singleton getInstance(){if(instance null) {synchronized (Singleto.class) {if(instance null){instance new Singleton() ;}} return instance;} …...
com.baomidou.mybatisplus.extension.service.IService用法详解及使用例子
IService 是 MyBatis-Plus 中的一个接口,提供了通用的 CRUD 操作,简化了数据库操作的代码。下面是 IService 的用法详解及示例代码。 1. 引入依赖 确保在你的 pom.xml 中添加了 MyBatis-Plus 的依赖: <dependency><groupId>co…...

植物健康,Spring Boot来保障
5系统详细实现 5.1 系统首页 植物健康系统需要登录才可以看到首页。具体界面的展示如图5.1所示。 图5.1 系统首页界面 5.2 咨询专家 可以在咨询专家栏目发布消息。具体界面如图5.2所示。 图5.2 咨询专家界面 5.3 普通植物检查登记 普通员工可以对普通植物检查登记信息进行添…...
mac-chrome提示您的连接不是私密连接
一、现象介绍 关闭代理之后就ok打开代理,就会提示您的连接不是私密连接 二、原因 由于代理部分的问题,无法找到正确的网站ip地址 三、解决方法 1、键盘直接输入thisisunsafe,可以继续访问网站,如果还是不对的话,那…...

028.爬虫专用浏览器-抓取#shadowRoot(closed)下的内容
一、什么是Shadow DOM Shadow DOM是一种在web开发中用于封装HTML标记、样式和行为的技术,以避免组件间的样式和脚本冲突。它允许开发者将网页的一部分隐藏在一个独立的作用域内,从而实现更加模块化和可维护的代码结构 二、js操作Shadow DOM // 获取宿…...

Serv00 免费虚拟主机 零成本搭建 PHP / Node.js 网站
本文首发于只抄博客,欢迎点击原文链接了解更多内容。 前言 Serv00 是一个提供免费虚拟主机的平台,包含了 3GB 的存储空间和 512MB 的内存空间,足够我们搭建一个 1IP 的小网站了。同时他还不限制每月的流量,并提供了 16 个数据库&…...
C#里使用ORM访问mariadb数据库
数据库,对于开发人员来说,是必须掌握的内容。 曾经我的老板对我说,只要会数据库的增删查改,就不会没有饭吃。 经过了20年多的工作经历,说明这个是铁的事实,毕竟计算机就是加工数据处理的而设计的。 数据就是信息,信息就是金钱,有了钱就可以有饭吃。 管理数据,就是…...

电商揭秘:商城积分体系简析
引言 商城积分体系划分是一个复杂而细致的过程,它旨在通过积分这一虚拟货币来激励用户行为、提升用户粘性,并促进商城的销售和用户活跃度。以下是对商城积分体系划分的详细解析: 一、积分获取方式 消费积分: 基础积分:…...
[OS] 终端控制(Terminal Control) 暂停执行线程(Suspend Executing Thread)
7. 终端控制(Terminal Control) 在终端中打印信息时,我们可以使用 ANSI 转义序列来控制光标的位置、清除屏幕等操作。\033 是转义字符,用于引导 ANSI 控制码来控制终端显示。可以将它理解为“命令前缀”,后面跟着具体…...

水陆两栖车应对应急事件发挥的作用_鼎跃安全
随着气候变化,城市内涝等问题日益严重。为了应对可能出现的洪水灾害,许多城市开始将水陆两栖车纳入应急救援装备体系。在暴雨引发城市积水时,水陆两栖车可以作为一种高效的救援和运输工具,及时疏散被困群众,运送应急物…...
CI/CD 流水线系统-开源框架Tekton
文章目录 CI/CD 流水线系统-开源框架Tekton什么是TektonTekton优点Tekton 组件介绍Tekton 概念术语 CI/CD 流水线系统-开源框架Tekton 什么是Tekton 官网:https://tekton.dev/ Tekton 是一个强大、灵活的构建 CI/CD 流水线系统的开源框架,允许开发者构建、测试和…...

Spring MVC(下)
博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多JavaEE知识 目录 1.响应 1.1 返回静态页面 1.2 返回数据ResponseBody 1.3 返回HTML代码⽚段 1.4 返回JSON 1.5 设置状态码 1.6 设置Header 2 . …...

开发涉及的安全规范整理
#1024程序员节|征文# 文章目录 前言安全场景与措施API调用方式鉴权参数校验日志打印数据保存加密 总结 前言 这篇文章我们来整理下写代码和方案设计中的安全规范问题,内容偏服务端,即使是入门的新人,如果你对安全有所了解会让成熟…...
驱动开发系列26 - Linux Graphics 调试 mesa 的 glDrawArrays (二)
目录 一:概述 二:Gallium3D 的工作流程 三:tc_draw_vbo 与 tc_call_draw_single 的关系: 四:tc_draw_vbo 与 tc_call_draw_single 的具体执行流程: 五:mesa中线程池设计介绍: 六:总结: 一:概述 众所周知,Mesa 的 Gallium3D 是一个图形驱动框架,它将图形管线…...

laya-spine动画的使用
laya2和laya3的spine动画在使用过程中并无太大区别,这里以laya3为例。 转换 首先将做好的spine动画按jison格式导出,导出完之后的文件应包括图集、图片和json类型的3个文件。然后再用laya的骨骼动画转换工具转换成laya内置的模式,转换后的文…...

Vue项目实战-新能源汽车可视化(一)(持续更新中)
一.项目代码 1.App.vue <template><!-- 模板--><div id"wrapper"><div style"width: 100%"><el-tabs v-model"activeName" id"tabs"> <!-- 标签栏里包含了三个标签面板,分别是研发与维…...
百度SEO前10关键词排名波动跟用户行为反馈有很大关系
大家好,我是林汉文(谷歌SEO专家),在百度SEO优化中,网站的排名并非一成不变,尤其是前10名的位置,更是动态变化。很多站长可能会发现,有时明明内容质量不错,外链也稳定&…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...