list的模拟实现(C++)

本文介绍了一个双向链表的模板实现,并包含了迭代器的支持。通过具体的代码示例展示了如何进行元素的插入、删除等操作,以及如何使用迭代器遍历链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <assert.h>
using namespace std;
template <class T>

//双向链表
struct ListNode{
	ListNode(const T& val = T())
	:_next(nullptr)
	,_prev(nullptr)
	,_val(val)
	{}
	ListNode<T>* _next;
	ListNode<T>* _prev;
	T _val;
};
//迭代器
template<class T,class Ref,class Ptr>
struct ListIterator{
	typedef ListNode<T>* pNode;
	typedef ListIterator<T,Ref,Ptr> self;
	pNode _node;
	//构造函数
	ListIterator(pNode node)
		:_node(node)
	{}
	//重载+
	self operator+(const T& n){
		for (int i = 0; i < n; i++){
			_node = _node->_next;
		}
		return *this;
	}
	//重载前置++
	self operator++(){
		_node = _node->_next;
		return *this;
	}
	//重载后置++,返回没有改变之前的值,然后自身++
	self operator++(int){
		self tmp(*this);
		_node = _node->_next;
		return *this;
	}
	//重载前置--
	self& operator--(){
		_node = _node->_prev;
		return *this;
	}
	//重载后置--
	self operator--(int){
		self tmp(*this);
		_node = _node->_prev;
		return *this;
	}
	//重载*
	Ref operator*(){
		return _node->_val;
	}
	//重载->
	Ptr operator->(){
		return &(operator*());
	}
	//重载!=,比较两个迭代器封装的结点是否一样
	bool operator!=(const self l){
		return _node != l._node;
	}
	//重载==
	bool operator==(const self l){
		return _node == l._node;
	}
};
template<class T>
class List{
public:
	typedef ListNode<T> Node;
	typedef ListNode<T>* pNode;
	//const对象不能调用非const对象成员函数,只能调用const成员函数
	//但是const成员函数operator++,operator--不能改变_node的值
	//导致const不能执行++,--
	typedef ListIterator<T, T&, T*> iterator;
	typedef ListIterator<T, const T&, const T*> const_iterator;
	//构造函数
	List(const T& val = T())
		:_head(new Node(val))
	{
		_head->_prev = _head;
		_head->_next = _head;
	}
	//拷贝构造函数
	//list需要实现深拷贝,否则浅拷贝只会拷贝对象模型中的头指针,不会拷贝
	//结点,析构函数释放结点的时候会造成二次释放,导致程序崩溃
	List(const List<T>& l){
		//首先创建头指针
		_head = new Node;
		_head->_prev = _head;
		_head->_next = _head;
		//遍历一遍,插入到list对象中去
		for (auto e : l){
			Push_Back(e);
		}
	}
	//赋值运算符
	List<T>& operator=( List<T>& l){
		////传统写法
		//if (this != &l){
		//	Clear();
		//	for (const auto& e : l){
		//		Push_Back(e);
		//	}
		//}
		//return *this;
		swap(_head, l._head);
		return *this;
	}
	
	//尾插,更新指向
	void Push_Back(const T& val ){
		pNode CurNode = new Node(val);
		assert(CurNode);
		pNode prev = _head->_prev;
		prev->_next = CurNode;
		CurNode->_prev = prev;
		CurNode->_next = _head;
		_head->_prev = CurNode;
	}
	//头插
	void PushFront(const T& val){
		Insert(begin(), val);
	}
	//头删
	void PopFront(){
		Erase(begin());
	}
	//尾删
	void PopBack(){
		Erase(--end());
	}
	//迭代器
	iterator begin(){
		return iterator(_head->_next);
	}
	iterator end(){
		return iterator(_head);
	}
	//const迭代器
	const_iterator begin()const{
		return const_iterator(_head->_next);
	}
	const_iterator end()const{
		return const_iterator(_head);
	}
	//在pos前面插入val
	void Insert(iterator pos, const T& val){
		pNode NewNode = new Node(val);
		pNode cur = pos._node;
		pNode prev = cur->_prev;
		prev->_next = NewNode;
		NewNode->_prev = prev;
		NewNode->_next = cur;
		cur->_prev = NewNode;
	}
	//删除指定结点的值
	//Erase:迭代器失效
	//获取Erase的返回值(当前被删除结点的下一个位置),更新迭代器
	iterator Erase(iterator pos){
		if (pos != end()){
			pNode cur = pos._node;
			pNode prev = cur->_prev;
			pNode next = cur->_next;
			prev->_next = next;
			next->_prev = prev;

			delete cur;
			//更新pos的位置
			pos = iterator(next);
		}
		return pos;
	}
	//删除全部
	void Clear(){
		if (_head){
			pNode cur = _head->_next;
			while (cur != _head){
				pNode next = cur->_next;
				delete cur;
				cur = next;
			}
			_head->_next = _head;
			_head->_prev = _head;
		}
	}
	//析构函数
	~List(){
		Clear();
		if (_head){
			delete _head;
			_head = nullptr;
		}
	}

private:
	pNode _head;
};
//构建date类
//class Date{
//	int _year;
//	int _month;
//	int _day;
//};
template<class T>
void PrintList(const List<T>& l){
	auto lit = l.begin();
	while (lit != l.end())
	{
		//*lit = 10;
		cout << *lit << " ";
		++lit;
	}
	cout << endl;
}

int main(){
	List<int> l;
	l.Push_Back(2);
	l.Push_Back(3);
	l.Push_Back(4);
	l.Push_Back(5);
	l.Push_Back(6);
	//l.PopBack();
	//l.Insert(l.begin(), 5);
	////l.Clear();
	//PrintList(l);
	//l.Erase(l.begin()+2);
	//PrintList(l);
	//l.PushFront(6);
	//l.PopFront();
	auto lit = l.begin();
	while (lit != l.end())
	{
		
		//*lit = 10;
		cout << *lit << " ";
		++lit;
	}
	/*PrintList(l);*/
	cout << endl;
	system("pause");
	return 0;
}
<think>首先,用户的问题是关于C++ list数据结构的模拟实现方法。用户意图是了解如何使用C++模拟实现list数据结构,这基于系统指令中的引用部分。 系统指令要求: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 参考的引用: - 引用[1]:提到了list模拟实现的框架,包括节点结构体模板、迭代器结构体模板、list结构体模板和测试函数。 - 引用[2]:详细描述了节点结构体的实现,包括数据域和指针域。 - 引用[3]:解释了__list_iterator结构体,用于封装迭代器,包括指针和运算符重载。 - 引用[4]:讨论了迭代器的解引用操作符重载。 我需要构建一个清晰的回答,逐步解释如何模拟实现C++list数据结构。listC++标准库中是一个双向链表。 回答结构: 1. **介绍**:简要说明list是什么,以及模拟实现的目的。 2. **核心组成部分**: - 节点结构体(ListNode):存储数据和前后指针。 - 迭代器类(iterator):封装节点指针,提供迭代功能。 - list类(list):管理链表,包括头尾指针和大小。 3. **详细实现**: - 节点结构体的定义。 - 迭代器类的定义,包括运算符重载(如++、--、*、->等)。 - list类的定义,包括构造函数、析构函数、插入、删除等操作。 4. **代码示例**:提供关键部分的代码片段,使用代码块格式。 5. **总结**:简要回顾实现要点。 6. **相关问题**:生成3-5个相关问题。 使用中文回答。 在引用部分末尾添加引用标识:[^1]、[^2]等。 生成相关问题: - 基于用户可能的兴趣,如性能分析、优化、应用场景等。 现在,组织内容: 1. **介绍**: - C++中的list是一个双向链表容器。模拟实现可以帮助理解其内部机制。 - 模拟实现主要包括三个部分:节点结构体、迭代器类和list类本身。 2. **节点结构体(ListNode)**: - 每个节点包含三个部分:数据域(_data)、指向前一个节点的指针(_prev)、指向后一个节点的指针(_next)。 - 使用模板以支持泛型。 - 示例代码: ```cpp template<class T> struct ListNode { ListNode<T>* _prev; ListNode<T>* _next; T _data; ListNode(const T& data = T()) : _prev(nullptr), _next(nullptr), _data(data) {} }; ``` 引用[2]描述了类似的实现。 3. **迭代器类(iterator)**: - 迭代器用于遍历链表,封装节点指针。 - 重载运算符:++(前置和后置)、--(前置和后置)、*(解引用)、->(成员访问)、==、!=等。 - 示例代码: ```cpp template<class T> struct __list_iterator { ListNode<T>* _node; __list_iterator(ListNode<T>* node) : _node(node) {} // 前置++ __list_iterator& operator++() { _node = _node->_next; return *this; } // 后置++ __list_iterator operator++(int) { __list_iterator tmp = *this; _node = _node->_next; return tmp; } // 前置-- __list_iterator& operator--() { _node = _node->_prev; return *this; } // 后置-- __list_iterator operator--(int) { __list_iterator tmp = *this; _node = _node->_prev; return tmp; } T& operator*() { return _node->_data; } T* operator->() { return &_node->_data; } bool operator!=(const __list_iterator& other) const { return _node != other._node; } bool operator==(const __list_iterator& other) const { return _node == other._node; } }; ``` 引用[3]和[4]提供了相关信息。 4. **list类(list)**: - 包含头节点指针(通常是一个哨兵节点,用于简化操作)。 - 成员函数:构造函数、析构函数、push_back、push_front、insert、erase、size等。 - 示例代码: ```cpp template<class T> class list { public: typedef __list_iterator<T> iterator; list() { _head = new ListNode<T>(); _head->_next = _head; _head->_prev = _head; _size = 0; } ~list() { clear(); delete _head; } iterator begin() { return iterator(_head->_next); } iterator end() { return iterator(_head); } void push_back(const T& value) { insert(end(), value); } void push_front(const T& value) { insert(begin(), value); } iterator insert(iterator pos, const T& value) { ListNode<T>* newNode = new ListNode<T>(value); ListNode<T>* cur = pos._node; ListNode<T>* prev = cur->_prev; prev->_next = newNode; newNode->_prev = prev; newNode->_next = cur; cur->_prev = newNode; _size++; return iterator(newNode); } iterator erase(iterator pos) { if (pos == end()) return pos; ListNode<T>* cur = pos._node; ListNode<T>* prev = cur->_prev; ListNode<T>* next = cur->_next; prev->_next = next; next->_prev = prev; delete cur; _size--; return iterator(next); } size_t size() const { return _size; } void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } } private: ListNode<T>* _head; // 哨兵节点 size_t _size; }; ``` 5. **总结**: - 模拟实现list涉及节点、迭代器和list类。 - 关键点是使用哨兵节点简化边界条件处理。 6. **相关问题**: - 1. 如何优化list实现的性能? - 2. list与vector在C++中的主要区别是什么? - 3. 在实际项目中,list有哪些常见应用场景? - 4. 如何处理list中的异常安全? - 5. 迭代器的失效机制在list中是如何工作的? 确保在回答中引用相关引用: - 当提到框架时,引用[1]。 - 当描述节点结构时,引用[2]。 - 当讨论迭代器时,引用[3]和[4]。 最终回答结构: - 开头介绍。 - 详细部分分步骤。 - 代码块。 - 总结。 - 相关问题。</think>### C++ list数据结构模拟实现方法 在C++中,`std::list`是一个双向链表容器,其模拟实现涉及三个核心部分:**节点结构体**、**迭代器类**和**list类**本身。下面我将逐步解释实现方法,确保内容清晰易懂。实现基于模板以支持泛型编程,并使用哨兵节点简化边界处理。关键代码使用C++语法,并遵循标准库的设计思想。 #### 1. **节点结构体(ListNode)** 节点是链表的基本单元,存储数据、前驱和后继指针。使用结构体模板定义: ```cpp template<class T> struct ListNode { ListNode<T>* _prev; // 指向前驱节点 ListNode<T>* _next; // 指向后继节点 T _data; // 存储数据 // 构造函数:初始化指针为nullptr,数据域使用默认值 ListNode(const T& data = T()) : _prev(nullptr), _next(nullptr), _data(data) {} }; ``` - **作用**:每个节点维护双向链接,支持高效插入和删除。 - **细节**:构造函数使用`T()`提供默认初始化,确保兼容各种数据类型[^2]。 #### 2. **迭代器类(__list_iterator)** 迭代器封装节点指针,提供类似指针的接口,支持遍历操作。重载运算符是关键: ```cpp template<class T> struct __list_iterator { ListNode<T>* _node; // 指向当前节点 // 构造函数:基于节点指针初始化 __list_iterator(ListNode<T>* node = nullptr) : _node(node) {} // 前置++:移动到下一个节点 __list_iterator& operator++() { _node = _node->_next; return *this; } // 后置++:返回当前迭代器后移动 __list_iterator operator++(int) { __list_iterator tmp = *this; // 拷贝当前状态 _node = _node->_next; return tmp; // 返回移动前的迭代器 } // 前置--:移动到前一个节点 __list_iterator& operator--() { _node = _node->_prev; return *this; } // 后置--:返回当前迭代器后移动 __list_iterator operator--(int) { __list_iterator tmp = *this; _node = _node->_prev; return tmp; } // 解引用:返回节点数据的引用 T& operator*() { return _node->_data; } // 箭头操作符:返回节点数据的指针 T* operator->() { return &_node->_data; } // 比较操作符:检查迭代器是否相等 bool operator==(const __list_iterator& other) const { return _node == other._node; } bool operator!=(const __list_iterator& other) const { return _node != other._node; } }; ``` - **作用**:实现类似标准迭代器的行为,包括`++`、`--`、`*`和`->`等操作。 - **细节**:后置`++`和`--`通过拷贝构造保留原状态,确保符合STL规范[^3][^4]。 #### 3. **list类(list)** list类管理整个链表,包括哨兵节点、大小维护和基本操作(如插入、删除)。使用哨兵节点(头节点)简化逻辑: ```cpp template<class T> class list { public: typedef __list_iterator<T> iterator; // 定义迭代器类型 // 构造函数:初始化哨兵节点(自环) list() { _head = new ListNode<T>(); // 创建哨兵节点 _head->_next = _head; // 初始化为自环 _head->_prev = _head; _size = 0; // 大小初始为0 } // 析构函数:释放所有节点 ~list() { clear(); // 清空链表 delete _head; // 删除哨兵节点 } // 迭代器接口 iterator begin() { return iterator(_head->_next); // 首元素是哨兵的下一个 } iterator end() { return iterator(_head); // 尾后位置是哨兵自身 } // 插入元素到指定位置前 iterator insert(iterator pos, const T& value) { ListNode<T>* newNode = new ListNode<T>(value); // 创建新节点 ListNode<T>* cur = pos._node; // 当前位置节点 ListNode<T>* prev = cur->_prev; // 前驱节点 // 链接新节点 prev->_next = newNode; newNode->_prev = prev; newNode->_next = cur; cur->_prev = newNode; _size++; // 更新大小 return iterator(newNode); // 返回新节点的迭代器 } // 删除指定位置元素 iterator erase(iterator pos) { if (pos == end()) return pos; // 不能删除哨兵 ListNode<T>* cur = pos._node; ListNode<T>* prev = cur->_prev; ListNode<T>* next = cur->_next; // 绕过当前节点 prev->_next = next; next->_prev = prev; delete cur; // 释放节点 _size--; // 更新大小 return iterator(next); // 返回下一个位置的迭代器 } // 添加元素到尾部 void push_back(const T& value) { insert(end(), value); } // 添加元素到头部 void push_front(const T& value) { insert(begin(), value); } // 清空链表 void clear() { iterator it = begin(); while (it != end()) { it = erase(it); // 逐个删除 } } // 获取链表大小 size_t size() const { return _size; } private: ListNode<T>* _head; // 哨兵节点(不存储数据) size_t _size; // 链表大小 }; ``` - **作用**:提供链表的核心功能,包括构造、析构、插入、删除和遍历。 - **细节**: - 哨兵节点`_head`形成自环,`begin()`指向第一个数据节点,`end()`指向哨兵,简化边界处理。 - `insert`和`erase`操作时间复杂度为$O(1)$,符合链表特性。 - `clear`和析构函数确保无内存泄漏[^1]。 #### 4. **测试示例** 简单测试代码: ```cpp #include <iostream> int main() { list<int> myList; myList.push_back(10); myList.push_front(20); auto it = myList.begin(); std::cout << *it << std::endl; // 输出20 it = myList.erase(it); std::cout << *it << std::endl; // 输出10 return 0; } ``` #### 总结 模拟实现C++ list的关键是: - **节点结构体**:管理数据和指针。 - **迭代器类**:封装遍历逻辑,通过运算符重载提供STL兼容接口。 - **list类**:使用哨兵节点简化操作,实现高效插入、删除和大小维护。 这种实现帮助深入理解链表底层机制,但实际开发中推荐使用标准库`std::list`以获得优化和安全性[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值