C++list的模拟实现

基本结构

首先明确一个问题,list是带头双向循环链表,既然是链表,那么我们就需要定义一个节点的结构体,然后既然是list的模拟实现,就需要定义一个list的类,根据带头双向循环链表的特点,还需要一个头节点,所以list的成员变量中必有一个头节点

下面是基本结构

cpp 复制代码
namespace bit
{
    template<class T>
    struct ListNode
    {
        ListNode<T>* _next;
        ListNode<T>* _prev;
        T _Date;
        ListNode(const T x=T())
        {
            _next=nullptr;
            _prev=nullptr;
            _Date=x;
        }
    };


    
    template<class T>
    calss list
    {
     public:
     list()
     {
        _head=new Node;
        _head->_next=_head;
        _head->_prev=_head;
     }

     private:
     typedef ListNode<T> Node;
     Node* _head;
        
    };


}

上面有一个问题,上面的那个定义节点要用struct,而不用class,原因就是上面的节点里面的任何元素随时都需要访问, 而struct里面的是默认共有的,当然在这里你也可以用calss,只是需要把所有的元素置成公有的

push_back()

向节点的尾部添加一个节点,基本的思路就是找到尾节点,申请新的节点,然后将新的节点连接就行了

cpp 复制代码
void push_back(const T x)
{
	Node* tail = _head->_prev;
	Node* newnode = new Node(x);
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = _head;
	_head->_prev = newnode;
}

迭代器

今天的这个迭代器会有一点特别,以前在string,vector里面的模拟实现里面,定义一个迭代器都是都是直接typedef一个int*,或者一个char*,让后直接对迭代器进行++或者--,但是,今天的这个是链表,结构在物理上都不是连续的,如何进行++或者--操作,这是不行的,唯一的方法就是对定义一个迭代器的类,然后对++或者--进行操作符的重载

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

		typedef ListNode<T> Node;
		typedef ListIterator<T> self;
		Node* _node;

	public:
		ListIterator(Node* node)
			:_node(node)
		{}

		
		self&operator++()
		{
			_node = _node->_next;
			return *this;
		}

		self operator++(int)
		{
			self temp(_node);
			_node = _node->_next;
			return temp;
		}

        self&operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		self operator--(int)
		{
			self temp(_node);
			_node = _node->_prev;
			return temp;
		}


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

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

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

		
	};

这样就可以对链表进行遍历了,当然了,这里的的begin()和end()函数还没有实现,可以在下面完整代码的list里面去查看

上面代码还有一个问题,你迭代器里面去重载一个--->有什么用

主要是为下面的情况做准备的

上面又又同学问了,啊,->这个操作符得出不是pos的地址吗,你这个怎么好直接就能去的出pos里面的成员变量的,其实上面的写法和被注释掉的代码是一样的,这里编译器是为了增强代码的可读性和美观性才这样省略出这样的,

const迭代器

const迭代器和非const迭代器其实是相差不大的,有人可能认为,在iterator前面加上一个const让他变成const iterator不就成为const迭代器了吗,那你就大错特错了

const迭代器是什么?是迭代器里面指向的内容不能被修改,直接加const不久变成迭代器不能被修改了,这里其实代码和非const迭代器是差不多的,唯一有一个地方需要改的就是限制解引用的返回值,让他变成const

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

	typedef ListNode<T> Node;
	typedef ListConstIterator<T> self;
	Node* _node;

public:
	ListConstIterator(Node* node)
		:_node(node)
	{}

	
	self&operator++()
	{
		_node = _node->_next;
		return *this;
	}

	self operator++(int)
	{
		self temp(_node);
		_node = _node->_next;
		return temp;
	}

	bool operator==(const self& s)
	{
		return _node == s._node;
	}
	bool operator!=(const self& s)    //记得参数里面加const,如果不加,会出现权限的放大问题
	{
		return _node != s._node;
	}

	const T& operator*()          //加const
	{
		return _node->_Date;
	}

	const T* operator->()        //加const
	{
		return &(_node->_Date);
	}

	
};

两个迭代器合一块

两个迭代器写一块,那不是太麻烦了一点,能不能写一个模板?答案是可以的

只需要在模板参数里面添加两个参数

然后下面函数的返回值稍微改动一下

最后关键的一步来了

在list定义迭代器里面的时候给不同的模板参数就行了

析构函数

cpp 复制代码
		~list()
		{
			list<T>::iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}

			delete _head;
			_head = nullptr;
		}

拷贝构造和赋值重载

cpp 复制代码
void empty_init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
}


list<T>& operator=(const list<T> l1)
{
	empty_init();                //这里记着要初始化
	swap(_head, l1._head);
	return *this;
}

上面的赋值运算符重载设计得很巧妙,首先明确的一个问题是要使用传值传参,后面直接交换两个_head的指向,因为传值传参会引发拷贝构造函数,后面把_head的指向给l1的拷贝构造了之后函数结束直接析构,这里就有点像让你干活,最后把你给杀了

cpp 复制代码
list(const list<T>& l1)
{
	empty_init();
	for (const auto &e : l1)
	{
		push_back(e);
	}


}

这里记得拷贝构造函数需要使用深拷贝,如果你不写拷贝构造函数得话,编译器生成的默认构造函数默认的是浅拷贝,函数调用结束了之后会发生同一块空间析构两次的问题,导致程序崩溃

写代码时的一个易错点

这里写代码的时候老是出现下面的问题:函数匹配问题,这一般都是由于权限的放大缩小问题

还有就是写范围for的时候尽量写引用,因为范围for实际上时赋值给e,赋值的话会拷贝产生一个临时对象,如果auto是自定义类型的话,拷贝量太大了,效率比较低

常规函数

cpp 复制代码
void erase(iterator pos)            //迭代器失效,因为被释放了
{
	Node* prev = pos._node->_prev;
	Node* next = pos._node->_next;
	prev->_next = next;
	next->_prev = prev;
	delete pos._node;
	pos._node = nullptr;
}

void insert(iterator&pos, T x)       //迭代器没有失效
{
	Node* newnode = new Node(x);
	Node* prev = pos._node->_prev;
	prev->_next = newnode;
	newnode->_prev = prev;
	newnode->_next = pos._node;
	pos._node->_prev = newnode;
}

void pop_back()
{
	Node* cur = _head->_prev;
	Node* prev = cur->_prev;
	prev->_next = _head;
	_head->_prev = prev;
	delete cur;
}

完整代码

cpp 复制代码
#include<iostream>
using namespace std;
namespace bit
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;
		T _Date;

		ListNode(const T date = T())
			:_Date(date)
			,_prev(nullptr)
			,_next(nullptr)
		{

		}

	};


	template<class T,class ref,class ptr>
	class ListIterator
	{

		typedef ListNode<T> Node;
		typedef ListIterator<T,ref,ptr> self;
	public:
		Node* _node;
	public:
		ListIterator(Node* node)
			:_node(node)
		{

		}

		self& operator++()
		{
			_node = _node->_next;
			return *this;

		}

		self operator++(int)
		{
			self temp(_node);
			_node = _node->_next;
			return temp;
		}

		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

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

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

		ref&operator*()
		{
			return _node->_Date;
		}
		
		ptr operator->()
		{
			return &(_node->_Date);
		}

	};

	/*template<class T>
	class ListConstIterator
	{

		typedef ListNode<T> Node;
		typedef ListConstIterator<T> self;
		Node* _node;

	public:
		ListConstIterator(Node* node)
			:_node(node)
		{}

		
		self&operator++()
		{
			_node = _node->_next;
			return *this;
		}

		self operator++(int)
		{
			self temp(_node);
			_node = _node->_next;
			return temp;
		}

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

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

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

		
	};*/


	template<class T>
	class list
	{
	public:
		typedef ListIterator<T, T&,T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;
		//typedef ListConstIterator<T> const_iterator;
		iterator begin()
		{
			return iterator(_head->_next);
		}

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

        const_iterator end()const
		{
			return const_iterator(_head);
		}
	
		iterator end()
		{
			return iterator(_head);
		}

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		

		list<T>& operator=(const list<T> l1)
		{
			empty_init();
			swap(_head, l1._head);
			return *this;
		}
		
		list()
		{
			empty_init();
		}
		void push_back(const T x)
		{
			Node* tail = _head->_prev;
			Node* newnode = new Node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
		}

		iterator erase(iterator pos)
		{
			Node* prev = pos._node->_prev;
			Node* next = pos._node->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._node;
			pos._node = nullptr;

			return iterator(next);
		}

		list(const list<T>& l1)
		{
			empty_init();
			for (const auto &e : l1)
			{
				push_back(e);
			}


		}

		~list()
		{
			list<T>::iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}

			delete _head;
			_head = nullptr;
		}

		bool empty()
		{
			return _head->_next == _head;
		}
		void insert(iterator&pos, T x)
		{
			Node* newnode = new Node(x);
			Node* prev = pos._node->_prev;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = pos._node;
			pos._node->_prev = newnode;
		}

		void pop_back()
		{
			Node* cur = _head->_prev;
			Node* prev = cur->_prev;
			prev->_next = _head;
			_head->_prev = prev;
			delete cur;
		}
	private:
		typedef ListNode<T> Node;
		Node* _head;
	};

	void test01()
	{
		list<int> l1;
		l1.push_back(10);
		l1.push_back(20);
		l1.push_back(30);
		l1.push_back(40);
		l1.push_back(50);
		l1.push_back(60);
		list<int>::iterator it = l1.begin();
		while (it != l1.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		
	}

	void func(const list<int>&s)
	{
		list<int>::const_iterator it = s.begin();
		while (it != s.end())
		{
			//(*it)++;
			cout << *it << " ";
			it++;
		}
	}

	void test02()
	{
		list<int> l1;
		l1.push_back(10);
		l1.push_back(20);
		l1.push_back(30);
		l1.push_back(40);
		func(l1);
	}

	struct pos
	{
		int _x;
		int _y;
		pos(int x=0,int y=0)
			:_x(x)
			,_y(y)
		{}
	};

	void test03()
	{
		list<pos> p;
		p.push_back(pos(1,2));
		p.push_back(pos(3,4));
		p.push_back(pos(5,6));
		list<pos>::iterator it = p.begin();
		//cout << it.operator->()->_x << " " << it.operator->()->_y << endl;
		cout << it->_x << " " << it->_y << endl;

	}

	void test04()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);
		for (auto &e : l1)
		{
			cout << e << " ";
		}
		cout << endl;
		
		list<int> l2 = l1;
		for (auto& e : l2)
		{
			cout << e << " ";
		}
		cout << endl;
		
		
	}


	void test05()
	{
		list<int> l1;
		l1.push_back(10);
		l1.push_back(20);
		l1.push_back(30);
		l1.push_back(40);

	}
}
相关推荐
Algorithm15763 分钟前
JVM是什么,与Java的关系是什么,以及JVM怎么实现的跨平台性
java·开发语言·jvm
Gnevergiveup4 分钟前
2024网鼎杯青龙组Web+Misc部分WP
开发语言·前端·python
LaoZhangGong12317 分钟前
使用常数指针作为函数参数
c++·经验分享
边疆.18 分钟前
C++类和对象 (中)
c语言·开发语言·c++·算法
yy_xzz20 分钟前
QT编译报错:-1: error: cannot find -lGL
开发语言·qt
你不讲 wood23 分钟前
使用 Axios 上传大文件分片上传
开发语言·前端·javascript·node.js·html·html5
林浔090631 分钟前
C语言部分输入输出(printf函数与scanf函数,getchar与putchar详解,使用Linux ubuntu)
c语言·开发语言
一颗甜苞谷1 小时前
开源一款基于 JAVA 的仓库管理系统,支持三方物流和厂内物流,包含 PDA 和 WEB 端的源码
java·开发语言·开源
CLCNboss1 小时前
Mac安装Ruby
开发语言·经验分享·笔记·macos·ruby
ai产品老杨1 小时前
深度学习模型量化原理
开发语言·人工智能·python·深度学习·安全·音视频