C++ list简单模拟实现

1.list的特点

list的本质就是带头双向链表,可以在常数时间复杂度进行插入删除的容器。

  • list和forward_list最主要的区别:forward_list是单链表,只能向前迭代,但list可以双向迭代
  • list比其他序列式容器(array,vector,deque)进行插入,移除元素的执行效率更好
  • list不支持任意位置的随机访问,要访问中间的元素,需要从头或者尾按序遍历

2.list中的节点

给于_val默认值,前后指针置空(使用struct,默认访问限定符是public)

cpp 复制代码
	//节点
	template <class T>
	struct ListNode
	{
		ListNode(const T& val = T())
		{
			_prev = nullptr;
			_next = nullptr;
			_val = val;
		}

		ListNode* _prev;//指向上一个元素
		ListNode* _next;//指向下一个元素
		T _val;		//值
	};

3.list中的迭代器

迭代器是一种设计模式 ,它在底层指针和用户接口之间增加了一个抽象层。这个抽象层让算法(如 std::sort, std::find)可以统一处理不同容器,而不需要知道容器内部是如何存储数据的。迭代器的实质就是指针,指向每个节点。(注意operator*返回的是T&)

cpp 复制代码
	//迭代器
	template<class T>
	struct List_Iterator
	{
		using Node = ListNode<T>;
		using self = List_Iterator<T>;

		List_Iterator(Node* node)
			:_node(node)
		{}
		//不需要析构函数,没有自己开辟空间,用默认构造就行

		//++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 it._node == _node;
		}

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

		const T& operator*()
		{
			return  _node->_val;
		}


		Node* _node;
	};

4.list的构造析构函数

  • 默认构造就是先创建一个头节点,让前后指针指向自己
  • 拷贝构造就是把一个链表节点的值全部尾插
cpp 复制代码
	template <class T>
	class List
	{
    public:
		using Node = ListNode<T>;
		using  Iterator = List_Iterator<T>;
		List()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			//前后指针指向自己
		}

		List(List<T>& list)//拷贝构造
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			for ( auto e : list)
			{
				push_back(e);
			}	
		}

		~List()//析构函数
		{
			clear();

			assert(_head);
			delete _head;
			_head = nullptr;
		}
		void clear()//释放所有节点
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
	 private:
		    Node* _head;//哨兵节点

    };

5.list的增删改

insert

在迭代器pos处插入val值。尾插和头插直接复用insert即可

cpp 复制代码
		Iterator insert(Iterator it, const T& val)
		{
			Node* newnode = new Node(val);
			Node* cur = it._node;
			Node* prev = it._node->_prev;

			//prev newnode cur
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			//返回新节点的迭代器
			return newnode;
		}
		//头插
		void push_front(const T& val)
		{
			insert(begin(), val);

		}

		//尾插
		void push_back(const T& val)
		{
			insert(end(), val);
		}

erase

删除迭代器pos处的值。对于头删和尾删同理复用

cpp 复制代码
		Iterator erase(Iterator it)
		{
			assert(it != _head);

			Node* cur = it._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;

			delete cur;

			return next;

		}
		//头删
		void pop_front()
		{
			erase(begin());
		}
		
		//尾删
		void pop_back()
		{
			erase(--end());
		}
相关推荐
YLCHUP2 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck3 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
思麟呀3 小时前
背包DP(01背包+完全背包)
c++·算法
旖旎夜光4 小时前
【C++ 基础入门】C++11 新特性(中):右值引用、移动语义与完美转发
开发语言·c++·笔记·学习
ShineWinsu5 小时前
对于Qt:QTabWidget常见属性的解析
开发语言·数据库·c++·qt·浏览器·qtabwidget·标签页
nice_lcj5205 小时前
LRU 缓存入门:它是什么、怎么用、面试怎么手写
java·数据结构·缓存·面试·lru
꧁细听勿语情꧂6 小时前
直接选择排序,堆排序,冒泡排序,递归快速排序、hoare版本、挖坑法、lomuto前后指针,非递归快速排序
c语言·开发语言·数据结构·算法
俊俊几年的6 小时前
动态规划(Dynamic Programming)详解:从入门到 LeetCode Hot 100
linux·c++·算法·leetcode·嵌入式·动态规划·c
Pniubi18 小时前
关于算法用现成数据结构和手撕
数据结构
老歌老听老掉牙1 天前
案例 7:二维 Rosenbrock 函数最小值(香蕉函数)
c++·pso