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());
		}
相关推荐
Darling噜啦啦4 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
clint4564 天前
C++进阶(1)——前景提要
c++
夜悊4 天前
C++代码示例:进制数简单生成工具
c++
郝学胜_神的一滴4 天前
CMake 021: IF 条件判据详诠
c++·cmake
_wyt0015 天前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
小小工匠5 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾5 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
один but you5 天前
constexpr函数
c++
Qres8215 天前
算法复键——树状数组
数据结构·算法
凡人叶枫5 天前
Effective C++ 条款41:了解隐式接口和编译期多态
java·开发语言·c++·effective c++