c++的学习之路:15、list(2)

本章主要是讲模拟实现list,文章末附上代码。

目录

一、创建思路

二、构造函数

 三、迭代器

四、增删

五、代码


一、创建思路

如下方代码,链表是由一块一块不连续的空间组成的,所以这里写了三个模板,一个是节点,一个是迭代器,分别放在struct创建的类,因为这个是可以直接访问,从下方代码可以看出我是在list里面定义了一个head,这个就是哨兵位头节点,然后在list_node里面写的就是节点的初始化,需要使用时直接new一个,_list_iterator这个就是迭代器写的地方了,这里也是直接写了两个一个普通的迭代器,一个const的。

namespace ly
{
    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;

        node* _node;

        _list_iterator(node* n)
            :_node(n)
        {}

    };

    template<class T>
    class list
    {
    public:
        typedef list_node<T> node;
        typedef _list_iterator<T, T&, T*> iterator;
        typedef _list_iterator<T, const T&, const T*> const_iterator;
    private:
        node* _head;
    };
}

二、构造函数

如下方代码所示就是我写的构造函数,因为这个链表是一个双向循环带头链表所以,直接new一个node在把哨兵位的next和prev指向自己,就创建出了一个链表,如下方图片可以看出创造出来了。

        list()
        {
            _head = new node;
            _head->_next = _head;
            _head->_prev = _head;
        }

 三、迭代器

这里是把迭代器能用到的都写了,例如解引用,就是利用这个节点指针直接访问就可以了,但是考虑到了可能访问常量指针所以,这里就是利用模板参数进行访问的,第二个就是相当于访问数据了,因为在流输出的时候正常是访问不到,因为迭代器访问的是这个节点的额指针,这时重载了一个->就可以正常访问了,++就是下一个节点的地址,也就是这个节点里面存入的next,前置和后置在之前文章中都说过,这里就不详细介绍了,后置就是价格int以作区分,--也是类似操作,==与!=直接判断节点的地址是否相同就可以了。

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

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

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

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

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

四、增删

再写数据结构的顺序表的时候就知道了,头插尾插头删尾删是可以直接使用inster的,所以这里是直接写了inster在进行调用的,代码如下,测试代码如下,结果如图,这里是直接调用insert的所以就不测试这个了。

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

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

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

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

        void pop_front()
        {
            erase(begin());
        }

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

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

void Test1()
    {
        list<int> l1;
        l1.push_back(1);
        l1.push_back(2);
        l1.push_back(3);
        l1.push_back(4);
        print(l1);
        l1.push_front(5);
        l1.push_front(6);
        l1.push_front(7);
        l1.push_front(8);
        print(l1);
        l1.pop_back();
        l1.pop_back();
        print(l1);
        l1.pop_front();
        l1.pop_front();
        print(l1);
    }

           

五、代码

#pragma once
#include <assert.h>
namespace ly
{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* n):_node(n){}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;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator==(const self& s){return _node == s._node;}bool operator!=(const self& s){return _node != s._node;}};template<class T>class list{public:typedef list_node<T> node;typedef _list_iterator<T, T&, T*> iterator;typedef _list_iterator<T, const T&, const T*> const_iterator;list(){_head = new node;_head->_next = _head;_head->_prev = _head;}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);}void push_back(const T& x){insert(end(),x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos,const T& x){node* cur = pos._node;node* prev = cur->_prev;node* new_node = new node(x);prev->_next = new_node;new_node->_prev = prev;new_node->_next = cur;cur->_prev = new_node;}void erase(iterator pos){assert(pos != end());node* prev = pos._node->_prev;node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;}private:node* _head;};void print(list<int> l){list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << ' ';it++;}cout << endl;}void Test1(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);print(l1);l1.push_front(5);l1.push_front(6);l1.push_front(7);l1.push_front(8);print(l1);l1.pop_back();l1.pop_back();print(l1);l1.pop_front();l1.pop_front();print(l1);}
}#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>using namespace std;#include "list.h"int main()
{ly::Test1();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/599200.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文速读】| 大语言模型平台安全:将系统评估框架应用于OpenAI的ChatGPT插件

本次分享论文为&#xff1a;LLM Platform Security: Applying a Systematic Evaluation Framework to OpenAI’s ChatGPT Plugins 基本信息 原文作者&#xff1a;Umar Iqbal, Tadayoshi Kohno, Franziska Roesner 作者单位&#xff1a;华盛顿大学圣路易斯分校&#xff0c;华盛…

OpenResty基于来源IP和QPS来限流

桶原理 我们可以想像: 有一只上面进水、下面匀速出水的桶&#xff0c;如果桶里面有水&#xff0c;那刚进去的水就要存在桶里等下面的水流完之后才会流出&#xff0c;如果进水的速度大于水流出的速度&#xff0c;桶里的水就会满&#xff0c;这时水就不会进到桶里&#xff0c;而…

【新手上路】C#联合Halcon第一个demo搭建

前言 学习Halcon目的是能够利用C#封装成一个视觉的上位机应用配合机器人或者过程控制来提高生产的效率&#xff0c;尤其是在检测外观和定位方面的应用。现在我们就来搭建第一个demo。让他们能够跑起来&#xff01; Halcon方面 打开Halcon软件&#xff0c;然后先随便写一个代…

electron-egg 如何把任意网站变成桌面软件

以前&#xff0c;开发一个桌面软件要花费大量的人力和时间。现在随着Electron的出现&#xff0c;大大简化了开发门槛。今天&#xff0c;给大家介绍一个工具&#xff0c;让你5分钟之内就把一个网站变成一个可安装的桌面软件。 所需工具 electron-egg是一个简单、快速、功能丰富…

日期时间相关的类

分界线jdk8 jdk8之前和之后分别提供了一些日期和时间的类&#xff0c;推荐使用jdk8之后的日期和时间类 Date类型 这是一个jdk8之前的类型&#xff0c;其中有很多方法已经过时了&#xff0c;选取了一些没有过时的API //jdk1.8之前的日期 Date Date date new Date(); // 从1970年…

解决 macOS 系统向日葵远程控制鼠标、键盘无法点击的问题

解决 macOS 系统向日葵远程控制鼠标\键盘无法点击的问题 1、首先正常配置&#xff0c;在系统偏好设置 - 安全性与隐私内&#xff0c;将屏幕录制、文件和文件夹、完全的磁盘访问权限、辅助功能全部都加入向日葵客户端 2、通过打开的文件访达&#xff0c;使用command shift G…

leetcode代码记录(下一个更大元素 I

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。 给你两个 没有重复元素 的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#x…

嵌入式学习49-单片机2

指令周期 1M 机器周期 12M &#xff08;晶体震荡器产生&#xff09; 中断两种方式 …

JVM—对象的创建流程与内存分配

JVM—对象的创建流程与内存分配 创建流程 对象创建的流程图如下&#xff1a; 对象的内存分配方式 内存分配的方式有两种&#xff1a; 指针碰撞&#xff08;Bump the Pointer&#xff09;空闲列表&#xff08;Free List&#xff09; 分配方式说明收集器指针碰撞&#xff08…

前端:SVG绘制流程图

效果 代码 html代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>SVG流程图示例</title><style>/* CSS 样式 */</style><script src"js/index.js"></script…

自然语言处理技术(Natural Language Processing)知识点

自然语言处理知识点 自然语言处理1. word2vec是什么2. 常用的NLP工具和软件3. 朴素贝叶斯分类器4. BiLSTM-CRF模型怎么去实现5. Bert模型实现NER6. 命名实体识别任务中&#xff0c;怎么去处理数据分布不均的问题&#xff1f;7. 用户问题检索相关文本时&#xff0c;具体都用了哪…

【CicadaPlayer】demuxer_service的简单理解

G:\CDN\all_players\CicadaPlayer-github-0.44\mediaPlayer\SMPMessageControllerListener.cppplayer的demuxer服务类 std::unique_ptr<demuxer_service> mDemuxerService{nullptr};根据option (Cicada::options),可以决定音视频的不同操作,通过 hander可以获得具体使…