STL——List常用接口模拟实现及其使用

news2024/12/23 1:07:41

认识list

list的介绍

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

list和vector的对比

vectorlist



动态顺序表,一段连续空间带头结点的双向循环链表


访
支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)




任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)




底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低


原生态指针对原生态指针(节点指针)进行封装




在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使


需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

基本框架

单个节点构建

	template<class T>
	class list_node {
	public:
		list_node<T>* _next;//后继指针
		list_node<T> *_prev;//前驱指针
		T _data;//节点的值
		list_node(const T& data = T())
			:_data(data)
			, _next(nullptr)
			,_prev(nullptr)
		{}
	};

List结构构建

class List {
		typedef list_node<T> Node;
	public:
		List(){
			_pHead = new Node();
			_pHead->_next = _pHead;
			_pHead->_prev = _pHead;
		}
};

push_back尾插

实现
void push_back(const T& data) {
			Node* newnode = new Node(data);
			Node* pTail = _pHead->_prev;//最后一个节点

			pTail->_next = newnode;
			newnode->_prev = pTail;//连接最后一个节点和新节点

			newnode->_next = _pHead;
			_pHead->_prev = newnode;//处理最后一个节点和第一个节点		}
使用
mylist::List<int> A;
	A.push_back(1);
	A.push_back(2);
	A.push_back(3);
	A.push_back(4);
	A.print();//这个是方便调试观察结果写出来的函数

在这里插入图片描述

迭代器的实现

在之前的容器string和vector的实现中,迭代器都是以指针的形式实现,但是在List模拟实现中又不是指针,因为List是一个链表,空间并不连续,指针的+或-并不能移动到数据的下一个位置。

迭代器的构造

	template <class T>
	class list_iterator {
		typedef list_node<T> Node;
	public:
		Node* _node
		list_iterator(Node* x): _node(x){}
	};

operator++

//前置++   (++it)
		iterator<T>& operator++() {
			_node = _node->_next;
			return *this;
		}
//后置++  (it++)
		iterator<T> operator++(int) {
			list_iterator<T> tmp(*this);
			_node = _node->_next;
			return tmp;
		}

operator*

//解引用
		T& operator*() {
			return _node->_data;
		}

operator !=

bool operator !=(const iterator& it) {
			return _node != it._node;
		}

在这里插入图片描述

const迭代器实现

如果这里要实现const迭代器,将之前的的代码复用再写一个const_list_iterator,然后在List再写一个const 的begin()和end()就可以了,但是这里有更优的写法,可以解决这些不必要的代码冗余

	class List {
	public:
		typedef list_node<T> Node;
		typedef list_iterator<T, T&, T*> iterator;
		typedef list_iterator<T, const T&, const T*> const_iterator;
		const_iterator begin() const {
			return const_iterator(_pHead->_next);
		}
		const_iterator end() const {
			return cosnt_iterator(_pHead);
		}
		.......
}
struct list_iterator {
		typedef list_node<T> Node;
		typedef list_iterator<T, Ref, Ptr> self;
		Ref& operator*() {
			return _node->_data;
		}
}

迭代器对List初始化

template<class Iterator>
		List(Iterator first, Iterator last) {
			_pHead = new Node();
			_pHead->_next = _pHead;
			_pHead->_prev = _pHead;

			while (first != last) {
				push_back(*first);
				first++;
			}
		}

增删查改

在 pos 位置前插入 - insert

	void insert(iterator pos, const T& x) {
			Node* cur = pos._node;     // 找到pos位置的结点
			Node* cur_prev = cur->_prev;     // 当前pos位置的前一个结点
			Node* new_node = new Node(x);  // 创建新节点

			cur_prev->_next = new_node;
			new_node->_prev = cur_prev;
			new_node->_next = cur;
			cur->_prev = new_node;
		}

push_front 头插

void push_front(const T& x) {
			insert(begin(), x); 
		}

在这里插入图片描述

删除 pos 位置的结点 erase

iterator erase(iterator pos) {
			assert(pos != end());   // 防止头结点被删除

			Node* cur = pos._node;   // pos
			Node* cur_prev = cur->_prev;   // pos的前驱
			Node* cur_next = cur->_next;   // pos的后继

			// 删除pos
			delete cur;
			cur_prev->_next = cur_next;
			cur_next->_prev = cur_prev;

			return iterator(cur_next);
		}

pop_back 尾删

void pop_back() {
	erase(_pHead->_prev);  // 删除最后一个元素
}

在这里插入图片描述

pop_front 头删

void pop_front() {
			erase(begin());  // 删除头结点的下一个结点->begin所指的位置
		}

在这里插入图片描述

clear 删除链表所有数据

void clear() {
			iterator cur = begin();
			while (cur != end()) {
				iterator del = cur++;
				delete del._node; 
			}
			//处理哨兵节点
			_pHead->_next = _pHead;
			_pHead->_prev = _pHead;
		}

在这里插入图片描述

析构函数和拷贝构造

默认的拷贝构造是浅拷贝,在这里是行不通的,万一调用析构函数,同一个空间就被释放两次了所以要对拷贝构造设计一下让其成为深拷贝的形式

析构

~List() {
	clear();
	delete _pHead;
	_pHead = nullptr;
}

拷贝构造


list(const list<T>& L) {
    _pHead = new Node();
	_pHead->_next = _pHead;
	_pHead->_prev = _pHead;
	List<T> tmp(L.begin(), L.end());
	swap(_pHead, tmp._pHead);  
}

在这里插入图片描述

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

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

相关文章

linux tcpdump的交叉编译以及使用

一、源码下载 官网&#xff1a;点击跳转 二、编译 1、解压 tar -xf libpcap-1.10.4.tar.xz tar -xf tcpdump-4.99.4.tar.xz 2、配置及编译 //libpcap&#xff1a; ./configure --hostarm-linux --targetarm-linux CCarm-linux-gcc --with-pcaplinux --prefix$PWD/build//t…

对象与JSON字符串互转

1、JSON字符串转化成JSON对象 JSONObject jsonobject JSON.parseObject(str); 或者 JSONObject jsonobject JSONObject.parseObject(str); 功能上是一样的&#xff0c;都是将JSON字符串&#xff08;str&#xff09;转换成JSON对象 jsonobject 。注意str一定得是以键值对存在…

STM32之HAL开发——电容按键

电容按键原理 电容器 (简称为电容) 就是可以容纳电荷的器件&#xff0c;两个金属块中间隔一层绝缘体就可以构成一个最简单的电容。如图 32_1 (俯视图)&#xff0c;有两个金属片&#xff0c;之间有一个绝缘介质&#xff0c;这样就构成了一个电容。这样一个电容在电路板上非常容…

二维数组求最大值(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i, j, max 0, row 0, colum 0;int arr[3][4] { {1, 2, 3}, {4, 5, 16}, {7, 8, 9} …

线上办理离婚快速离婚,无需双方见面异地可办

现在离婚有两种方式 一种是协议离婚&#xff0c;双方都同意的情况下&#xff0c;可以去民政局协议离婚&#xff0c;有30天冷静期&#xff0c;冷静期过后需要双方再次去民政局办理离婚手续。 另一种是诉讼离婚&#xff0c;一方不同意离婚&#xff0c;可以选择诉讼离婚。可以全…

Vue 3 路由机制详解与实践

一、路由的理解 路由是指导用户界面导航的一种机制。它通过映射 URL 到应用程序的不同视图组件来实现页面间的切换和导航。 二、路由基本切换效果 路由基本切换效果指的是当用户在应用程序中进行页面导航时&#xff0c;通过路由可以实现页面的切换&#xff0c;从而展示不同的…

ICMP详解

3 ICMP ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制报文协议&#xff09;是一个差错报告机制&#xff0c;是TCP/IP协议簇中的一个重要子协议&#xff0c;通常被IP层或更高层协议&#xff08;TCP或UDP&#xff09;使用&#xff0c;属于网络层协议…

CTF(web方向)--md5的“===”和“==”的绕过

一、PHP弱类型说明 1.简介 php是一种弱类型语言&#xff0c;对数据的类型要求并不严格&#xff0c;可以让数据类型互相转换。 在php中有两种比较符号: 一种是 &#xff0c;另外一种是 &#xff0c;都是用来比较两个数值是否相等的操作符&#xff0c;但他们也是有区别的: &a…

Linux 小技巧1

目录 一. 统计文件的总行数二. 获取从第二行开始的内容三. 合并两个文件为一个文件四. 统计指定列唯一值的数量五. 列出文件的绝对路径六. 获取除了空白行和注释之外的部分 一. 统计文件的总行数 ⏹非压缩文件 统计当前文件夹下csv文件的行数 wc -l ./*.csv统计指定文件夹下…

想要应聘前端工程师——学习路线指南

前端工程师学习路线 按照前端岗位需求,以优先学习工作更需要,面试更常考的内容为原则,由浅入深,层层铺垫,与时俱进,可以较容易地总结出前端学习路线图: HTML / CSS / JavaScript 基础学习 《Web 入门》 MDN 权威入门指南,HTML / CSS / JavaScript 快速上手 《CSS 世界…

面试中算法(链表)

链表相关的题 有一个单向链表&#xff0c;链表中有可能出现“环”&#xff0c;如图所示&#xff0c;如何用程序来判断该链表是否为有环链表呢? 对于这道题&#xff0c;有一个很巧妙的方法&#xff0c;这个方法利用了两个指针。 首先创建两个指针pi和p2(在Python里就是两个对象…

【问题分析】TaskDisplayArea被隐藏导致的黑屏以及无焦点窗口问题【Android 14】

1 问题描述 用户操作出的偶现的黑屏以及无焦点窗口问题。 直接原因是&#xff0c;TaskDisplayArea被添加了eLayerHidden标志位&#xff0c;导致所有App的窗口不可见&#xff0c;从而出现黑屏和无焦点窗口问题&#xff0c;相关log为&#xff1a; 这个log是MTK添加的&#xff0…

目标检测——YOLOv8算法解读

作者&#xff1a;Ultralytics公司 代码&#xff1a;https://github.com/ultralytics/ultralytics YOLO系列算法解读&#xff1a; YOLOv1通俗易懂版解读、SSD算法解读、YOLOv2算法解读、YOLOv3算法解读、YOLOv4算法解读、YOLOv5算法解读、YOLOR算法解读、YOLOX算法解读、YOLOv6算…

7. Django 模型与数据库

第7章 模型与数据库 Django对各种数据库提供了很好的支持, 包括PostgreSQL, MySQL, SQLite和Oracle, 而且为这些数据库提供了统一的API方法, 这些API统称为ORM框架. 通过使用Django内置的ORM框架可以实现数据库连接和读写操作. 本章以SQLite数据库为例, 分别讲述Django的模型…

统一威胁情报如何赋能SOC应对复杂威胁?

安全运营中心&#xff08;SOC&#xff09;是组织网络安全战略的核心组成部分&#xff0c;扮演着至关重要的角色。其负责实时监控整个IT基础设施&#xff0c;以检测、响应和预防各类网络安全威胁。网络安全威胁日益复杂且多变的数字化时代&#xff0c;攻击平面泛化、基础设施复杂…

10天精通Python爬虫:详细路线速成,开启兼职副业新篇章!

爬虫&#xff0c;即网络爬虫&#xff0c;是一种自动化程序&#xff0c;用于从互联网上抓取数据。在现代信息社会&#xff0c;爬虫技术广泛应用于数据分析、搜索引擎优化、竞品分析等领域。学习爬虫不仅可以提高数据处理能力&#xff0c;还可以为未来的职业发展打下坚实基础。 …

java基础之java容器-Collection,Map

java容器 java容器分类一. Collection1. List①. ArrayList② . LinkedList③ . Vector 2. Queue队列①. LinkedList②. PriorityQueue 3. Set集合①. HashSet②. TreeSet 二. Map1. HashMap2.TreeMap3. Hashtable java容器分类 java容器分为两大类&#xff0c;分别是Collecti…

修复所有 bug 并不能解决所有问题

原文&#xff1a;jeffpsherman - 2024.04.08 在软件领域&#xff0c;如同在制造业&#xff0c;有些问题是由于 bug 或“特殊原因”引发的&#xff0c;而有些则是“常见原因”&#xff0c;这是由于系统设计和实现的性质所导致的。修复 bug 就是移除特殊原因&#xff0c;消除 bu…

项目经理学习PMP对自己工作有多大帮助?

PMP是一种项目管理认证&#xff0c;也是最流行和含金量较高的认证之一。因此&#xff0c;你问它对项目管理有多大帮助&#xff0c;我可以说PMP可以被视为量身定制给项目管理岗人员的一个证书&#xff0c;你能理解它的重要性吗&#xff1f; 随着国家经济建设由基础设施向高端产业…

新闻 | 电子系协同智能中心与昌平区未来高教园及多所高校开展交流,共话智能无人平台建设

2024年4月8日&#xff0c;清华大学电子工程系在北京昌平两岸共盈科技产业园电子系地空协同智能无人平台基地成功举办“美团杯”智能无人机挑战赛&#xff0c;清华大学电子系党委书记沈渊、昌平区未来城管委会校城融合处处长熊玉川、清华大学团委副书记黄峰等出席。此外来自昌平…