list的模拟实现

cpp 复制代码
iterator insert(iterator pos,const T&x)
{
	Node* newnode = new Node(x);
	Node* cur = pos._node;//先存一下pos位置的指针
	Node* prev = cur->_prev;//再存一下没插入之前pos前面节点的指针

	cur->_prev = newnode;
	newnode->_next = cur;
	newnode->_prev = prev;
	prev->_next = newnode;
	
	return newnode;
}

开头

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

//结点,节点要要公开,用struct就好

cpp 复制代码
//结点,节点要要公开,用struct就好
template<class T>
struct list_node
{
	list_node<T>* _prev;
	list_node<T>* _next;
	T _val;

	//结点的初始化构造函数
	list_node(const T&val=T())//写成T(),是为了防止T不是内置类型
		:_val(val)
		,_prev(nullptr)
		,_next(nullptr)
	{}
};

迭代器指针

cpp 复制代码
template<class T, class  Ref,   class Ptr>
struct __list_node
{
    typedef list_node<T> Node;
    typedef __list_node<T,Ref,Ptr>  KKK;
};

指向节点的指针

cpp 复制代码
Node* _node;

构造函数

cpp 复制代码
__list_node(Node*node)
	:_node(node)
{}

operator*

cpp 复制代码
Ref& operator*()//这里是const迭代器的关键,返回的*it,就是指向的位置
{
	return _node->_val;
}

这里是const迭代器的关键,返回的*it,就是指向的位置

operator++

cpp 复制代码
	KKK operator++()
	{
		_node = _node->_next;
		return *this;
	}
    KKK operator++(int)
    {
	    KKK tmp(*this);
	    _node = _node->_next;
	    return tmp;
    }

operator--

cpp 复制代码
KKK operator--()
{
	_node = _node->_prev;
	return *this;
}	
KKK operator--(int)
{
	Node tmp(*this);
	_node = _node->_prev;
	return tmp;
}

operator!=

cpp 复制代码
bool operator!=(const KKK&it)//里面必须加const,因为返回的end()具有常性
{
	return _node != it._node;
}

里面必须加const,因为返回的end()具有常性

operator->

cpp 复制代码
Ptr* operator->()//这里的T*也分为const和不带const,所以加上class Ptr
{
	return &_node->_val;
}

这里的T*也分为const和不带const,所以加上class Ptr

list

cpp 复制代码
template<class T>
class list
{


private:
	Node*_head;
	size_t _size;
};

三参数的传递

(第二个const迭代器,第三个是带不带const的->的重载)

cpp 复制代码
	typedef list_node<T> Node;//相当于私有

public:
	//迭代器
	typedef __list_node<T,T&, T*>  iterator;//第三个T*是为了operator->的重载
	//const迭代器
	//typedef const __list_node<T>  const_iterator;这种写法是错误的,因为const后的对象无法
	                                                                             //修改,但我们需要的是it++,可以被修改,不被修改的是
														//指向的内容不被修改
														
	//正确写法
	typedef __list_node<T,const T&,const T*>  const_iterator;

//const迭代器
//typedef const __list_node<T> const_iterator;这种写法是错误的,因为const后的对象无法修改,但我们需要的是it++,可以被修改,不被修改的是指向的内容不被修改

构造函数

cpp 复制代码
list()
{
	_head = new Node;// new一个类型就相当于new一个这个类型的空间
	_head->_next = _head;
	_head->_prev = _head;
}

new一个类型就相当于new一个这个类型的空间

尾插

cpp 复制代码
void push_back(const T&x)
{
	//Node* newnode = new Node(x);//初始化为x,()是初始化[]开空间
	先把尾结点和头结点连接起来
	//Node* tail = _head->_prev;//一开始时,_head_>prev指向的是自己
	//tail->_next = newnode;//一开始要把_head的prev和next与newnode连接起来

	//newnode->_prev = tail;
	//newnode->_next = _head;
	//_head->_prev = newnode;

	insert(end(),x);
}

iterator begin

cpp 复制代码
iterator begin()
{
	return _head->_next;
}

iterator end()

cpp 复制代码
iterator end()
{
	return _head;//左闭右开
}

const_iterator

cpp 复制代码
const_iterator begin() const
{
	return _head->_next;
}
const_iterator end() const
{
	return _head;//左闭右开
}

pos位置前插入

cpp 复制代码
iterator insert(iterator pos,const T&x)
{
	Node* newnode = new Node(x);
	Node* cur = pos._node;//先存一下pos位置的指针
	Node* prev = cur->_prev;//再存一下没插入之前pos前面节点的指针

	cur->_prev = newnode;
	newnode->_next = cur;
	newnode->_prev = prev;
	prev->_next = newnode;
	
	return newnode;
}

pos位置的删除

cpp 复制代码
iterator erase(iterator pos)
{
	assert(pos != end());//不能删除头结点

	Node* cur = pos._node;//存一下pos的节点指针
	Node* prev = cur->_prev;//存一下pos之前节点的指针
	Node* next = cur->_next;//存一下pos下一个节点的指针

	//连接pos位置前一个和后一个的节点,然后释放pos的空间
	prev->_next = next;
	next->_prev = prev;
	
	delete[]  cur;//加不加[]都行
	return next;
}

pop_back

cpp 复制代码
void pop_back() 
{ 
	erase(--end()); 
}

push_front

cpp 复制代码
void push_front(const T& val) 
{ 
	insert(begin(), val); 
}

pop_front

cpp 复制代码
void pop_front() 
{ 
	erase(begin()); 
}

size

cpp 复制代码
size_t size()
{
	size_t i = 0;
	auto it = begin();
	while (it != end())
	{
		i++;
		it++;
	}
	return i;
}

clear

clear,顺序表vector不需要释放空间,因为没法单独释放一部分空间,而链表list可以

cpp 复制代码
void clear()
{
	auto it = begin();
	while (it != end())
	{
		it = erase(it);//这里会释放空间
		it++;
	}
	_size = 0;
}

erase(it);//这里会释放空间

析构

cpp 复制代码
~list()
{
	clear();
	delete _head;
	_head = nullptr;
}

拷贝构造

必须要有一个头结点

cpp 复制代码
list(const list<T>& It)
{
	//必须要有一个头结点
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
	auto it = It.begin();
	while (it != It.end())
	{
		push_back(*it);
		it++;
	}
}

swap

cpp 复制代码
	void swap(list<T>&It)
	{
		std::swap(_head, It._head);
		std::swap(_size, It._size);
	}

operator=

cpp 复制代码
//=的实现
list<T>& operator=(list<T>&It)
{
	//现代写法用swap
	swap(It);
	return *this;
}

总代码加测试

cpp 复制代码
//list.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace Ljw
{
	//结点,节点要要公开,用struct就好
	template<class T>
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _val;

		//结点的初始化构造函数
		list_node(const T&val=T())//写成T(),是为了防止T不是内置类型
			:_val(val)
			,_prev(nullptr)
			,_next(nullptr)
		{}
	};

	//迭代器指针
	template<class T, class  Ref,   class Ptr>
	struct __list_node
	{
		typedef list_node<T> Node;
		typedef __list_node<T,Ref,Ptr>  KKK;

		Node* _node;//指向节点的指针

		//构造函数
		__list_node(Node*node)
			:_node(node)
		{}

		Ref& operator*()//这里是const迭代器的关键,返回的*it,就是指向的位置
		{
			return _node->_val;
		}

		KKK operator++()
		{
			_node = _node->_next;
			return *this;
		}
		KKK operator--()
		{
			_node = _node->_prev;
			return *this;
		}	
		KKK operator--(int)
		{
			Node tmp(*this);
			_node = _node->_prev;
			return tmp;
		}


		KKK operator++(int)
		{
			KKK tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		bool operator!=(const KKK&it)//里面必须加const,因为返回的end()具有常性
		{
			return _node != it._node;
		}

		Ptr* operator->()//这里的T*也分为const和不带const,所以加上class Ptr
		{
			return &_node->_val;
		}
	};

	//list,带头双向链表
	template<class T>
	class list
	{
		typedef list_node<T> Node;//相当于私有

	public:
		//迭代器
		typedef __list_node<T,T&, T*>  iterator;//第三个T*是为了operator->的重载
		//const迭代器
		//typedef const __list_node<T>  const_iterator;这种写法是错误的,因为const后的对象无法
		                                                                             //修改,但我们需要的是it++,可以被修改,不被修改的是
															//指向的内容不被修改
															
		//正确写法
		typedef __list_node<T,const T&,const T*>  const_iterator;


		//构造函数
		list()
		{
			_head = new Node;// new一个类型就相当于new一个这个类型的空间
			_head->_next = _head;
			_head->_prev = _head;
		}

		//尾插
		void push_back(const T&x)
		{
			//Node* newnode = new Node(x);//初始化为x,()是初始化[]开空间
			先把尾结点和头结点连接起来
			//Node* tail = _head->_prev;//一开始时,_head_>prev指向的是自己
			//tail->_next = newnode;//一开始要把_head的prev和next与newnode连接起来

			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;

			insert(end(),x);
		}
		iterator begin()
		{
			return _head->_next;
		}
		iterator end()
		{
			return _head;//左闭右开
		}
		const_iterator begin() const
		{
			return _head->_next;
		}
		const_iterator end() const
		{
			return _head;//左闭右开
		}

		//pos位置前插入
		iterator insert(iterator pos,const T&x)
		{
			Node* newnode = new Node(x);
			Node* cur = pos._node;//先存一下pos位置的指针
			Node* prev = cur->_prev;//再存一下没插入之前pos前面节点的指针

			cur->_prev = newnode;
			newnode->_next = cur;
			newnode->_prev = prev;
			prev->_next = newnode;
			
			return newnode;
		}

		//pos位置的删除
		iterator erase(iterator pos)
		{
			assert(pos != end());//不能删除头结点

			Node* cur = pos._node;//存一下pos的节点指针
			Node* prev = cur->_prev;//存一下pos之前节点的指针
			Node* next = cur->_next;//存一下pos下一个节点的指针

			//连接pos位置前一个和后一个的节点,然后释放pos的空间
			prev->_next = next;
			next->_prev = prev;
			
			delete[]  cur;//加不加[]都行
			return next;
		}

		void pop_back() 
		{ 
			erase(--end()); 
		}
		void push_front(const T& val) 
		{ 
			insert(begin(), val); 
		}
		void pop_front() 
		{ 
			erase(begin()); 
		}
		size_t size()
		{
			size_t i = 0;
			auto it = begin();
			while (it != end())
			{
				i++;
				it++;
			}
			return i;
		}

		//clear,顺序表vector不需要释放空间,因为没法单独释放一部分空间,而链表list可以
		void clear()
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);//这里会释放空间
				it++;
			}
			_size = 0;
		}

		//析构
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		//拷贝构造//必须要有一个头结点
		list(const list<T>& It)
		{
			//必须要有一个头结点
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			auto it = It.begin();
			while (it != It.end())
			{
				push_back(*it);
				it++;
			}
		}

		void swap(list<T>&It)
		{
			std::swap(_head, It._head);
			std::swap(_size, It._size);
		}

		//=的实现
		list<T>& operator=(list<T>&It)
		{
			//现代写法用swap
			swap(It);
			return *this;
		}


	private:
		Node*_head;
		size_t _size;
	};

	void test1()
	{
		list<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);

		list<int>::iterator it = v.begin();//这里是浅拷贝,不是赋值,迭代器不用写析构
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
	}
	void test2()
	{
		list<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(3);

		v.insert(v.begin(), 9);
		
		auto it = v.begin();
		while(it!=v.end())
		{
			if (*it % 3 == 0)
			{
				it = v.erase(it);
			}
			else
			{
				it++;
			}	
		}
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
		cout<<v.size();
	}

	void test3()
	{
		list<int>v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(3);

		list<int>v1(v);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int>v2;
		v2.push_back(10);
		v2.push_back(20);
		v2.push_back(30);
		v1 = v2;
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}
相关推荐
WG_177 分钟前
C++多态
开发语言·c++·面试
ahauedu1 小时前
案例分析-Stream List 中取出值最大的前 5 个和最小的 5 个值
数据结构·list
Charles Ray2 小时前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码2 小时前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
X同学的开始3 小时前
数据结构之二叉树遍历
数据结构
AIAdvocate6 小时前
Pandas_数据结构详解
数据结构·python·pandas
jiao000016 小时前
数据结构——队列
c语言·数据结构·算法
kaneki_lh6 小时前
数据结构 - 栈
数据结构
铁匠匠匠6 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
C-SDN花园GGbond6 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法