【c++】STl-list使用&&list模拟实现

主页:醋溜马桶圈-CSDN博客

专栏:c++_醋溜马桶圈的博客-CSDN博客

gitee:mnxcc (mnxcc) - Gitee.com

目录

[1. list的介绍及使用](#1. list的介绍及使用)

[1.1 list的介绍](#1.1 list的介绍)

[1.2 list的使用](#1.2 list的使用)

[1.2.1 list的构造](#1.2.1 list的构造)

[1.2.2 list iterator的使用](#1.2.2 list iterator的使用)

[1.2.3 list capacity](#1.2.3 list capacity)

[1.2.4 list element access](#1.2.4 list element access)

[1.2.5 list modifiers](#1.2.5 list modifiers)

[1.2.6 list的迭代器失效](#1.2.6 list的迭代器失效)

[2. list的深度剖析及模拟实现](#2. list的深度剖析及模拟实现)

[2.1 模拟实现list](#2.1 模拟实现list)

[2.2 list的反向迭代器](#2.2 list的反向迭代器)

[3. list与vector的对比](#3. list与vector的对比)

[3.1 list与vector的对比](#3.1 list与vector的对比)

[3.2 对比list排序和vector排序](#3.2 对比list排序和vector排序)


1. list的介绍及使用

1.1 list****的介绍

list - C++ Reference (cplusplus.com)

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

1.2 list****的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口

1.2.1 list的构造

1.2.2 list iterator的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

【注意】

  1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
  2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

1.2.3 list capacity

1.2.4 list element access

1.2.5 list modifiers

cpp 复制代码
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(4);
	lt.push_back(4);
	lt.push_back(4);

1.2.6 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了 。因为list的底层结构为带头结点的双向循环链表 ,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

2. list的深度剖析及模拟实现

2.1模拟实现list

cpp 复制代码
#pragma once
#include <assert.h>
#include <iostream>
using namespace std;

namespace dc
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;
		T _data;

		ListNode(const T& x=T())
		:_next(nullptr)
		,_prev(nullptr)
		,_data(x)
		{}
	};
	//typedef ListIterator<T, T&, T*> iterator;
	//typedef ListIterator<T, const T&, const T*> const_iterator;
	template<class T,class Ref,class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

		Node* _node;
		
		ListIterator(Node* node)
			:_node(node)
		{}
		//*it
		//T& operator*()
		Ref operator*()
		{
			return _node->_data;
		}
		//it->
		//T* operator->()
		Ptr operator->()
		{
			return &_node->_data;
		}
		//++it
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//it++
		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		//--it
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		//it--
		Self operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const Self& it)
		{
			return _node != it._node;
		}		
		bool operator==(const Self& it)
		{
			return _node == it._node;
		}
	};

	//template<class T>
	//struct ListConstIterator
	//{
	//	typedef ListNode<T> Node;
	//	typedef ListConstIterator<T> Self;
	//	Node* _node;
	//	ListConstIterator(Node* node)
	//		:_node(node)
	//	{}
	//	//*it
	//	const T& operator*()
	//	{
	//		return _node->_data;
	//	}
	//	//it->
	//	const T* operator->()
	//	{
	//		return &_node->_data;
	//	}
	//	//++it
	//	Self& operator++()
	//	{
	//		_node = _node->_next;
	//		return *this;
	//	}
	//	//it++
	//	Self operator++(int)
	//	{
	//		Self tmp(*this);
	//		_node = _node->_next;
	//		return tmp;
	//	}
	//	//--it
	//	Self& operator--()
	//	{
	//		_node = _node->_prev;
	//		return *this;
	//	}
	//	//it--
	//	Self operator--(int)
	//	{
	//		Self tmp(*this);
	//		_node = _node->_prev;
	//		return tmp;
	//	}
	//	bool operator!=(const Self& it)
	//	{
	//		return _node != it._node;
	//	}
	//	bool operator==(const Self& it)
	//	{
	//		return _node == it._node;
	//	}
	//};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;
	public:
		//typedef ListIterator<T> iterator;
		//typedef ListConstIterator<T> const_iterator;
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;

		iterator begin()
		{
			//return _head->_next;

			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			//return _head->_next;

			return _head->_next;
		}
		const_iterator end() const
		{
			return _head;
		}
		//初始化头结点
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}
		list()
		{
			empty_init();
		}
		//lt2(lt1)
		list(const list<T>& lt)
		{
			empty_init();
			for (auto& e : lt)
			{
				push_back(e);
			}
		}
		//需要析构,一般就需要自己写深拷贝
		//不需要析构,默认浅拷贝就可以
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		//lt1=lt3
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		//void push_back(const T& x)
		//{
		//	Node* newnode = new Node(x);
		//	Node* tail = _head->_prev;
		//	tail->_next = newnode;
		//	newnode->_prev = tail;
		//	_head->_prev = newnode;
		//	newnode->_next = _head;
		//}
		void push_back(const T& x)
		{
			insert(end(), x);
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}
		void insert(iterator pos, const T& val)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(val);
			Node* prev = cur->_prev;
			prev->_next = newnode;
			newnode->_next = cur;
			cur->_prev = newnode;
			newnode->_prev = prev;
			_size++;
		}
		iterator erase(iterator pos)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;
			delete cur;
			_size--;
			return iterator(next);
		}
		size_t size() const
		{
			return _size;
		}
		bool empty()
		{
			return _size == 0;
		}


	private:
		Node* _head;
		size_t _size;
	};
}

2.2 list****的反向迭代器

通过前面例子知道,反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可

cpp 复制代码
template<class Iterator>
class ReverseListIterator
{
	// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量
	// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
	// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:
	typedef typename Iterator::Ref Ref;
	typedef typename Iterator::Ptr Ptr;
	typedef ReverseListIterator<Iterator> Self;
public:
	//
	// 构造
	ReverseListIterator(Iterator it) : _it(it) {}
	//
	// 具有指针类似行为
	Ref operator*() {
		Iterator temp(_it);
		--temp;
		return *temp;
	}
	Ptr operator->() { return &(operator*()); }
	//
	// 迭代器支持移动
	Self& operator++() {
		--_it;
		return *this;
	}
	Self operator++(int) {
		Self temp(*this);
		--_it;
		return temp;
	}
	Self& operator--() {
		++_it;
		return *this;
	}
	Self operator--(int)
	{
		Self temp(*this);
		++_it;
		return temp;
	}
	//
	// 迭代器支持比较
	bool operator!=(const Self& l)const { return _it != l._it; }
	bool operator==(const Self& l)const { return _it != l._it; }
	Iterator _it;
};

3. list与vector的对比

3.1 list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不 同,其主要不同如下

3.2 对比list排序和vector排序

cpp 复制代码
void test2()
{
	srand(time(0));
	const int N = 1000000;
	list<int> lt1;
	list<int> lt2;
	vector<int> v;
	for (int i = 0; i < N; i++)
	{
		auto e = rand()+i;
		lt1.push_back(e);
		v.push_back(e);
	}
	int begin1 = clock();
	//排序
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();
	printf("vector sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}
相关推荐
C-SDN花园GGbond1 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处2 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ3 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
leon6253 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林3 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
white__ice4 小时前
2024.9.19
c++
天玑y4 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
锦亦之22334 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt
我是苏苏4 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
姜太公钓鲸2334 小时前
c++ static(详解)
开发语言·c++