c++之List容器的模拟实现

news/2025/1/24 7:52:42/

注:最终代码以汇总的为准

1.前言

在之前的数据结构中,我们曾模拟实现过链表的数据结构,但是十分麻烦,全篇都暴露了链表的底层结构-----指针,但是从使用的角度,使用者并不关心你用的底层结构是啥,而且编写者也不愿意将所有的底层结构暴露出来,为此,在此文章中,我们将充分发挥c++的优势,将指针包装一下,变为迭代器

2.基本框架的实现

基本结构包括链表的创建,包括链表结点的创建,结点的初始化,以及对底层结构----指针的封装,还有一些基本操作,例如++,==,!=,还有解引用操作等。

我们将造链表的文件放在List.h文件中,等下在test.cpp文件中进行测试。

如下代码是基本的结构代码:(具体功能没实现)

#include <assert.h>
namespace rens
{template<class T>struct list_node              //定义结点结构{list_node* <T> _next;list_node* <T> _prev;T _data;list_node(const T& x=T()):_next(nullptr),_prev(nullptr),_data(x){}};
}
template <class T>
struct list_iterator
{typedef list_node<T> Node;Node* _node;list_iterator(Node* node):_node(node){}T& operator*()                  //模拟指针的解引用{return _node->_data;        //返回的是数据,类型为T}T* operator->()                 //解引用的->,这个较为特殊{return &_node->_data;}list_iterator<T>& operator++(){_node = _node->_next;return *this;              //++操作返回的是下一个结点}bool operator!=(const list_iterator<T>& it){return this->_node != it._node;}bool operator==(const list_node<T>& it){return this->_node == it._node;}
};template <class T>
class list
{typedef list_node<T> Node;
public:typedef list_iterator<T> iterator;
private:Node* _head;size_t _size;
};

 但是,上述代码如果要是想遍历const对象是,由于我们的迭代器不是const迭代器,不能满足我们的需求,为此我们还要将上述代码cv一份,并改为const迭代器。

const迭代器代码如下:

template <class T>
struct const_list_iterator
{typedef list_node<T> Node;Node* _node;const_list_iterator(Node* node):_node(node){}const T& operator*()                  //模拟指针的解引用{return _node->_data;        //返回的是数据,类型为T}const T* operator->()                 //解引用的->,这个较为特殊{return &_node->_data;}const_list_iterator<T>& operator++(){_node = _node->_next;return *this;              //++操作返回的是下一个结点}bool operator!=(const const_list_iterator<T>& it){return this->_node != it._node;}bool operator==(const const_list_iterator<T>& it){return this->_node == it._node;}
};

但是,通过对比(对比图如下),我们发现这两段代码重复度太大了,仅仅是返回类型的区别,这样写未免太浪费,所以我们将其改造一下!

 

改造想法:既然我们的类型就是有无const的区别,那我们不妨利用模板,对其进行改造,添加一个Ref,即reference,引用&以及Ptr,即pointer,指针

为了方便改造,我们将原来的list_iterator<T>给typedef一下,省的总改!

 改造代码:

template <class T, class Ref, class Ptr>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;Node* _node;list_iterator(Node* node):_node(node){}Ref operator*()                  //模拟指针的解引用{return _node->_data;        //返回的是数据,类型为T}Ptr operator->()                 //解引用的->,这个较为特殊{return &_node->_data;}self& operator++()           //前置++,返回的是引用, this指向的对象不销毁。{_node = _node->_next;return *this;              //++操作返回的是下一个对象}self operator++(int)          //后置++,返回的是一个临时对象,tmp出函数就销毁了{self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it){return this->_node != it._node;}bool operator==(const self& it){return this->_node == it._node;}
};

 其余功能的实现:

	template <class T>class list{typedef list_node<T> Node;public://typedef list_iterator<T> iterator;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){iterator it(_head->_next);      //我们的链表是双向循环链表,_head可以理解为哨兵结点return it;}iterator end(){return iterator(_head);}const_iterator begin()const        //加上const关键字表示该函数不会修改类的任何成员变量,即它是一个常量成员函数{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}list(std::initializer_list<T> lt){empty_init();for (auto& e : lt){push_back(e);}}//lt2(lt1)list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}//lt1=lt3list<T>& operator=(list<T> lt){swap(lt);return *this;}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}size_t size()const{return _size;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(--end());}void insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* nextnode = cur->_next;Node* prevnode = cur->_prev;prevnode->_next = nextnode;nextnode->_prev = prevnode;delete cur;--_size;return iterator(nextnode);}private:Node* _head;size_t _size;};
}

3.代码的汇总及实现

这是List.h文件 

#include <assert.h>
#include <initializer_list>
#include<iostream>
#include<algorithm>
namespace rens
{template<class T>struct list_node              //定义结点结构{list_node<T>* _next;list_node<T>* _prev;T _data;list_node(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};template <class T, class Ref, class Ptr>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;Node* _node;list_iterator(Node* node):_node(node){}Ref operator*()                  //模拟指针的解引用{return _node->_data;        //返回的是数据,类型为T}Ptr operator->()                 //解引用的->,这个较为特殊{return &_node->_data;}self& operator++()           //前置++,返回的是引用, this指向的对象不销毁。{_node = _node->_next;return *this;              //++操作返回的是下一个对象}self operator++(int)          //后置++,返回的是一个临时对象,tmp出函数就销毁了{self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it){return this->_node != it._node;}bool operator==(const self& it){return this->_node == it._node;}};//template <class T>//struct list_iterator//{//	typedef list_node<T> Node;//	Node* _node;//	list_iterator(Node* node)//		:_node(node)//	{}////	T& operator*()                  //模拟指针的解引用//	{//		return _node->_data;        //返回的是数据,类型为T//	}////	T* operator->()                 //解引用的->,这个较为特殊//	{//		return &_node->_data;//	}////	list_iterator<T>& operator++()//	{//		_node = _node->_next;//		return *this;              //++操作返回的是下一个结点//	}////	bool operator!=(const list_iterator<T>& it)//	{//		return this->_node != it._node;//	}////	bool operator==(const list_node<T>& it)//	{//		return this->_node == it._node;//	}//};//template <class T>//struct const_list_iterator//{//	typedef list_node<T> Node;//	Node* _node;//	const_list_iterator(Node* node)//		:_node(node)//	{}////	const T& operator*()                  //模拟指针的解引用//	{//		return _node->_data;        //返回的是数据,类型为T//	}////	const T* operator->()                 //解引用的->,这个较为特殊//	{//		return &_node->_data;//	}////	const_list_iterator<T>& operator++()//	{//		_node = _node->_next;//		return *this;              //++操作返回的是下一个结点//	}////	bool operator!=(const const_list_iterator<T>& it)//	{//		return this->_node != it._node;//	}////	bool operator==(const const_list_iterator<T>& it)//	{//		return this->_node == it._node;//	}//};template <class T>class list{typedef list_node<T> Node;public://typedef list_iterator<T> iterator;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){iterator it(_head->_next);      //我们的链表是双向循环链表,_head可以理解为哨兵结点return it;}iterator end(){return iterator(_head);}const_iterator begin()const        //加上const关键字表示该函数不会修改类的任何成员变量,即它是一个常量成员函数{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}list(std::initializer_list<T> lt){empty_init();for (auto& e : lt){push_back(e);}}//lt2(lt1)list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}//lt1=lt3list<T>& operator=(list<T> lt){swap(lt);return *this;}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}size_t size()const{return _size;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(--end());}void insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* nextnode = cur->_next;Node* prevnode = cur->_prev;prevnode->_next = nextnode;nextnode->_prev = prevnode;delete cur;--_size;return iterator(nextnode);}private:Node* _head;size_t _size;};
}

这是test.cpp文件

#include"list.h"using namespace std;void test1()
{rens::list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);rens::list<int>::iterator it1 = lt1.begin();while (it1 != lt1.end()){*it1 += 1;cout << *it1 << " ";++it1;}cout << endl;
}
void print(const rens::list<int>& lt)
{// const迭代器本身可以修改,指向内容不能修改rens::list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}
struct A
{A(int a1=1,int a2=1):_a1(a1),_a2(a2){}int _a1;int _a2;
};
void test2()
{rens::list<A> lt2;lt2.push_back({ 1,1 });lt2.push_back({ 2,2 });lt2.push_back({ 3,3 });lt2.push_back({ 4,4 });rens::list<A>::iterator it = lt2.begin();while (it != lt2.end()){cout << it->_a1 << "," << it->_a2 << endl;++it;}cout << endl;rens::list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);print(lt1);
}
void test3()
{rens::list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);for (auto e : lt1){cout << e << " ";}cout << endl;lt1.push_front(5);lt1.push_front(6);for (auto e : lt1){cout << e << " ";}cout << endl;lt1.pop_back();lt1.pop_back();lt1.pop_front();lt1.pop_front();for (auto e : lt1){cout << e << " ";}cout << endl;lt1.pop_back();lt1.pop_back();for (auto e : lt1){cout << e << " ";}cout << endl;
}
void test4()
{rens::list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);for (auto e : lt1){cout << e << " ";}cout << endl;rens::list<int> lt2(lt1);lt1.clear();for (auto e : lt1){cout << e << " ";}cout << endl;for (auto e : lt2){cout << e << " ";}cout << endl;rens::list<int> lt3 = { 10,20,30,40 };lt1 = lt3;for (auto e : lt1){cout << e << " ";}cout << endl;
}
int main()
{//test1();//test2();//test3();test4();return 0;
}

 


http://www.ppmy.cn/news/1565718.html

相关文章

Java如何向http/https接口发出请求

用Java发送web请求所用到的包都在java.net下&#xff0c;在具体使用时可以用如下代码&#xff0c;你可以把它封装成一个工具类 import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Outpu…

【力扣:新动计划,编程入门 —— 题解 ②】

—— 25.1.23 1512. 好数对的数目 给你一个整数数组 nums 。 如果一组数字 (i,j) 满足 nums[i] nums[j] 且 i < j &#xff0c;就可以认为这是一组 好数对 。 返回好数对的数目。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1,1,3] 输出&#xff1a;4 解释&#xff…

Java设计模式—观察者模式

观察者模式 目录 观察者模式1、什么是观察者模式&#xff1f;2、观察者模式优缺点及注意事项&#xff1f;3、观察者模式实现&#xff1f;4、手写线程安全的观察者模式&#xff1f; 1、什么是观察者模式&#xff1f; - 实例&#xff1a;现实生活中很多事物都是依赖存在的&#x…

专业学习|最优化理论(目标函数、约束条件以及解题三板斧)

个人学习使用资料,请勿传播,若有侵权联系删除,资料来源:fairy girl。 一、最优化理论:让决策更科学,让模型更高效 (一)什么是最优化理论? 最优化理论是数学的一个分支,它研究如何在一定约束条件下找到使目标函数达到最大值或最小值的最优解。 关键概念:最优化理论的…

rclone整合alist

rclone整合alist 安装/配置rclone脚本安装rcloneetc/systemd/system/rclonehttp.serviceetc/systemd/system/rclone-alist.serviceconfig授权下载HTTP web介面文件启用服务并设置开机启动 安装/配置rclone 脚本安装rclone sudo -v ; curl https://rclone.org/install.sh | su…

【MySQL】存储引擎有哪些?区别是什么?

频率难度60%⭐⭐⭐⭐ 这个问题其实难度并不是很大&#xff0c;只是涉及到的相关知识比较繁杂&#xff0c;比如事务、锁机制等等&#xff0c;都和存储引擎有关系。有时还会根据场景选择不同的存储引擎。 下面笔者将会根据几个部分尽可能地讲清楚 MySQL 中的存储引擎&#xff0…

深度学习-92-大语言模型LLM之基于langchain的模型IO的模型调用

文章目录 1 Model的输入输出2 langchain支持的模型3 调用Ollama模型3.1 设置环境变量3.2 大语言模型LLM(OllamaLLM)3.2.1 生成文本补全3.2.2 流式生成文本补全3.3 聊天模型(ChatOllama)3.3.1 内置的消息类型3.3.2 HumanMessage和SystemMessage3.3.3 元组方式构成消息列表3.3.4 …

【Trunk接口配置】

Trunk接口配置 Trunk即干道链路&#xff0c;用来在不同设备&#xff08;交换机和交换机&#xff0c;交换机和路由器&#xff09;间承载所有vlan数据。不属于任何一个具体的vlan&#xff0c;可以传输所有vlan的数据&#xff0c;也可以传输指定vlan的数据。 设备IPvlanPC110.1.…