当前位置: 首页 > news >正文

C++:模拟实现STL的list

目录

一.list类

1.list的创建节点

2.list迭代器的运算符操作

3.list的构造函数及析构

4.list的迭代器

5.list的插入及删除

二.整体代码

1.list.h

2.list.cpp


在上一节已经了解list在库中的用法,在这里实现list的底层逻辑

一.list类

1.list的创建节点

template<class T>
struct __list_node
{__list_node* _next;__list_node* _prev;T _data;__list_node(const T& x = T()) :_data(x), _next(nullptr), _prev(nullptr) {}
};

2.list迭代器的运算符操作

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;}Ptr operator->(){return &_node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(*this);//_node = _node->_next;++(*this);return tmp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(*this);//_node = _node->_prev;--(*this);return tmp;}bool operator!=(const Self& it) {return _node != it._node;}bool operator==(const Self& it) {return _node == it._node;}
};

3.list的构造函数及析构

1.list的构造函数

因为list是双向带头循环链表,所以我们只需要让头节点的prev和next都指向头节点

//双向带头循环链表
list()
{_head = new Node;_head->_next = _head;_head->_prev = _head;
}

2.list的拷贝构造

拷贝构造时我们需要创建一个新的节点,将值依次插入尾部即可,可以通过迭代器遍历,也可以通过范围for

list(const list<T>& lt)
{_head = new Node;_head->_next = _head;_head->_prev = _head;/*const_iterator it = lt.begin();while (it != lt.end()){push_back(*it);++it;}*/for (auto ch : lt)push_back(ch);
}

3.list的赋值

赋值是不需要创建新节点的,因为已经有了,所以只需要插入值即可

list<T>& operator=(const list<T>& lt)
{if (this != &lt){clear();for (auto ch : lt)push_back(ch);}return *this;
}

4.list的析构

析构在这里我们用到clear函数,clear是清空所以数据,只留头节点,但是析构头节点也要释放

~list()
{clear();delete _head;_head = nullptr;
}void clear()
{iterator it = begin();while (it != end()){erase(it++);}
}

4.list的迭代器

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

5.list的插入及删除

push_back

尾部插入一个值时只需要将节点前后连接,并更新头节点的prev

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;
}

insert

任意插入一个值,我们需要创建一个节点,并将其与前后节点连接

void insert(iterator pos, const T& x)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//prev newnode curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;
}

当我们实现了insert后,对于push_back和push_front都可以通过调用insert实现

	void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}

erase

对于erase来说,我们只需要找到删除节点的prev和next,将他们两个连接,删除当前节点即可

void erase(iterator pos)
{assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;
}

实现erase后,pop_back和pop_front调用erase即可

void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}

二.整体代码

1.list.h

#pragma once
#include <iostream>
#include<assert.h>
using namespace std;namespace wzyl
{template<class T>struct __list_node{__list_node* _next;__list_node* _prev;T _data;__list_node(const T& x = T()) :_data(x), _next(nullptr), _prev(nullptr) {}};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;}Ptr operator->(){return &_node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(*this);//_node = _node->_next;++(*this);return tmp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(*this);//_node = _node->_prev;--(*this);return tmp;}bool operator!=(const Self& it) {return _node != it._node;}bool operator==(const Self& it) {return _node == it._node;}};template<class T>class list{typedef __list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;iterator begin() {return iterator(_head->_next);}iterator end() {return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//双向带头循环链表list(){_head = new Node;_head->_next = _head;_head->_prev = _head;}list(const list<T>& lt){_head = new Node;_head->_next = _head;_head->_prev = _head;/*const_iterator it = lt.begin();while (it != lt.end()){push_back(*it);++it;}*/for (auto ch : lt)push_back(ch);}list<T>& operator=(const list<T>& lt){if (this != &lt){clear();for (auto ch : lt)push_back(ch);}return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){erase(it++);}}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;*/insert(end(), x);}void pop_back(){erase(--end());}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//prev newnode curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;}void erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;}private:Node* _head;};void test_list1(){list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);list<int>::iterator it = ls.begin();while (it != ls.end()){cout << *it << " ";++it;}cout << endl;}struct Date{int _year = 0;int _month = 1;int _day = 1;};void test_list2(){list<Date> ls;ls.push_back(Date());ls.push_back(Date());list<Date>::iterator it = ls.begin();while (it != ls.end()){cout << it->_year << "-" << it->_month << "-" << it->_day << endl;++it;}cout << endl;}void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}void test_list3(){list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);ls.insert(ls.begin(), 0);ls.push_front(-1);print_list(ls);ls.pop_front();ls.pop_back();print_list(ls);ls.clear();ls.push_back(1);print_list(ls);}void test_list4(){list<int> lst1;lst1.push_back(1);lst1.push_back(2);lst1.push_back(3);lst1.push_back(4);list<int> lst2(lst1);print_list(lst2);list<int> lst3;lst3.push_back(10);lst3.push_back(20);lst3.push_back(30);lst3.push_back(40);lst1 = lst3;print_list(lst1);}
}

2.list.cpp

#include"list.h"int main()
{wzyl::test_list1();//wzyl::test_list2();//wzyl::test_list3();//wzyl::test_list4();return 0;
}


http://www.mrgr.cn/news/68203.html

相关文章:

  • Axure设计之三级联动选择器教程(中继器)
  • Flutter中文字体设置指南:打造个性化的应用体验
  • mysql5.7安装SSL报错解决(2),总结
  • 大数据-211 数据挖掘 机器学习理论 - 逻辑回归 scikit-learn 实现 max_iter 分类方式选参数
  • 10-Query Filtering 与多字符串多字段查询
  • Git 的分支管理
  • 鸿蒙NEXT开发笔记(十二)仿微信聊天App的图片转BASE64串
  • Nginx 配置文件详解
  • 【最高分数与最低分数 】
  • 理解Web登录机制:会话管理与跟踪技术解析(三)-过滤器Filter
  • 【系统设计】数据库压缩技术详解:从基础到实践(附Redis内存优化实战案例)
  • 软件测试基础十四(python 类与对象)
  • 问:SpringFramwork都有哪些模块?
  • 论文1—《基于卷积神经网络的手术机器人控制系统设计》文献阅读分析报告
  • C++学习笔记----11、模块、头文件及各种主题(一)---- 模板概览与类模板(1)
  • 网络编程(一):UDP socket api => DatagramSocket DatagramPacket
  • 对话框(Dialog)
  • W3C HTML 活动
  • [数组排序] 1122. 数组的相对排序
  • 插入迭代器
  • 口播博主必装的五个App推荐,尤其是程序猿博主
  • 查缺补漏----内部排序算法排序趟数和比较次数
  • SQLI LABS | Less-33 GET-Bypass AddSlashes()
  • RCE漏洞分析
  • OSS和FastDFS的区别
  • 【如何在 Linux 和 Android 系统中杀死进程】