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

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

一、创建思路

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


namespace ly
{
    template
    struct list_node
    {
        list_node* _next;
        list_node* _prev;
        T _data;
        list_node(const T& x = T())
            :_next(nullptr)
            , _prev(nullptr)
            , _data = x
        {}
    };
    template
    struct _list_iterator
    {
        typedef list_node node;
        typedef __list_iterator self;
        node* _node;
        node* _node;
        _list_iterator(node* n)
            :_node(n)
        {}
    };
    template
    class list
    {
    public:
        typedef list_node node;
        typedef _list_iterator iterator;
        typedef _list_iterator 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 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();
}


目录
相关文章
|
5天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
24 4
2023/11/10学习记录-C/C++对称分组加密DES
|
6天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
22 7
|
14天前
|
存储 编译器 C++
C++ initializer_list&&类型推导
在 C++ 中,`initializer_list` 提供了一种方便的方式来初始化容器和传递参数,而右值引用则是实现高效资源管理和移动语义的关键特性。尽管在实际应用中 `initializer_list&&` 并不常见,但理解其类型推导和使用方式有助于深入掌握现代 C++ 的高级特性。
16 4
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
59 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
2月前
|
存储 算法 C++
【C++打怪之路Lv10】-- list
【C++打怪之路Lv10】-- list
22 1
|
2月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
65 5
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
27 1
|
2月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
73 2
|
2月前
|
存储 缓存 C++
C++番外篇——list与vector的比较
C++番外篇——list与vector的比较
26 0