C++模拟实现List迭代器详解

C++模拟实现List迭代器详解

前言

本文将介绍如何在 C++ 中实现 List 容器的迭代器(iterator),并通过两个示例说明其用法。迭代器可以遍历容器中的元素,并灵活地进行读写操作。这是 C++ 中常用的操作之一,对于理解 C++ 中的容器非常有帮助。

实现 List 迭代器

概述

在 C++ 中,每个容器都有其对应的迭代器,List 也不例外。List 迭代器可以通过访问器实现,其定义和实现如下:

template<typename T>
struct Node{
    T data;
    Node* pre;
    Node* nxt;

    // 构造函数和析构函数
    Node():pre(nullptr),nxt(nullptr){}
    Node(T d, Node* p, Node* n):data(d),pre(p),nxt(n){}
    ~Node(){}

    // 拷贝构造函数和拷贝赋值运算符
    Node(const Node& n):data(n.data),pre(n.pre),nxt(n.nxt){}
    Node& operator=(const Node& n)
    {
        if(this != &n)
        {
            data = n.data;
            pre = n.pre;
            nxt = n.nxt;
        }
        return *this;
    }
};

template <typename T>
class List; // 为了提前声明 List,这里只定义迭代器

template <typename T>
class ListIterator{
    friend class List<T>;
private:
    Node<T>* curr;
public:
    ListIterator(){}
    ListIterator(Node<T>* ptr):curr(ptr){}
    ListIterator(const ListIterator<T>& li):curr(li.curr){}
    ~ListIterator(){}

    bool operator==(const ListIterator<T>& li) const
    {
        return curr == li.curr;
    }

    bool operator!=(const ListIterator<T>& li) const
    {
        return curr != li.curr;
    }

    T& operator*() const
    {
        return curr->data;
    }

    ListIterator<T>& operator++()
    {
        curr = curr->nxt;
        return *this;
    }

    ListIterator<T>& operator++(int)
    {
        ListIterator<T> tmp = *this;
        curr = curr->nxt;
        return tmp;
    }

    ListIterator<T>& operator--()
    {
        curr = curr->pre;
        return *this;
    }

    ListIterator<T>& operator--(int)
    {
        ListIterator<T> tmp = *this;
        curr = curr->pre;
        return tmp;
    }

    ListIterator<T>& operator=(const ListIterator<T>& li)
    {
        if(this != &li)
        {
            curr = li.curr;
        }
        return *this;
    }
};

代码中的 ListIterator 包含了指向节点的 Node<T>* curr 指针,以及实现迭代器相关操作的成员函数。该类的构造函数、拷贝构造函数、析构函数和赋值运算符都十分简单。重载操作符包括比较运算符(==!=)、解引用运算符(*)、前后缀自增和自减运算符(++--)。需要注意的是,自增和自减运算符需要实现前后缀两种操作方法。

实现 List

下面是一个简单的 List 实现,该实现包含了常用的操作函数(插入、删除和排序)以及迭代器相关函数。

template<typename T>
class List{
public:
    typedef ListIterator<T> iterator;

    List();
    List(const List<T>& l);
    ~List();
    List<T>& operator=(const List<T>& l);

    bool empty() const;
    int size() const;
    void clear();
    void reverse();
    void swap(List<T>& l);

    T& front();
    const T& front() const;
    T& back();
    const T& back() const;

    void push_front(const T& data);
    void push_back(const T& data);
    iterator insert(iterator pos, const T& data);
    iterator erase(iterator pos);
    void sort();

    iterator begin();
    iterator end();
private:
    int len;
    Node<T>* head;
    Node<T>* tail;
};

template<typename T>
List<T>::List():len(0),head(new Node<T>),tail(new Node<T>)
{
    head->nxt = tail;
    tail->pre = head;
}

template<typename T>
List<T>::List(const List<T>& l):len(0),head(new Node<T>),tail(new Node<T>)
{
    head->nxt = tail;
    tail->pre = head;
    for(auto it=l.begin(); it!=l.end(); ++it)
        push_back(*it);
}

template<typename T>
List<T>::~List()
{
    clear();
    delete head;
    delete tail;
}

template<typename T>
List<T>& List<T>::operator=(const List<T>& l)
{
    if(this == &l)
        return *this;

    clear();
    for(auto it=l.begin(); it!=l.end(); ++it)
        push_back(*it);

    return *this;
}

template<typename T>
bool List<T>::empty() const
{
    return len == 0;
}

template<typename T>
int List<T>::size() const
{
    return len;
}

template<typename T>
void List<T>::clear()
{
    while(!empty())
        erase(begin());
}

template<typename T>
void List<T>::reverse()
{
    Node<T>* curr = head->nxt;
    while(curr != tail)
    {
        std::swap(curr->pre, curr->nxt);
        curr = curr->pre;
    }
    std::swap(head, tail);
}

template<typename T>
void List<T>::swap(List<T>& l)
{
    std::swap(len, l.len);
    std::swap(head, l.head);
    std::swap(tail, l.tail);
}

template<typename T>
T& List<T>::front()
{
    return *begin();
}

template<typename T>
const T& List<T>::front() const
{
    return *begin();
}

template<typename T>
T& List<T>::back()
{
    return *(--end());
}

template<typename T>
const T& List<T>::back() const
{
    return *(--end());
}

template<typename T>
void List<T>::push_front(const T& data)
{
    insert(begin(), data);
}

template<typename T>
void List<T>::push_back(const T& data)
{
    insert(end(), data);
}

template<typename T>
typename List<T>::iterator List<T>::insert(iterator pos, const T& data)
{
    Node<T>* p = pos.curr;
    Node<T>* q = new Node<T>(data, p->pre, p);
    p->pre->nxt = q;
    p->pre = q;
    return iterator(q);
}

template<typename T>
typename List<T>::iterator List<T>::erase(iterator pos)
{
    Node<T>* p = pos.curr;
    iterator ret = iterator(p->nxt);
    p->pre->nxt = p->nxt;
    p->nxt->pre = p->pre;
    delete p;
    return ret;
}

template<typename T>
void List<T>::sort()
{
    if(empty()) return;

    std::list<T> tmpList;
    for(auto it=begin(); it!=end(); ++it)
        tmpList.push_back(*it);

    tmpList.sort();

    clear();
    for(auto it:tmpList)
        push_back(it);
}

template<typename T>
typename List<T>::iterator List<T>::begin()
{
    return iterator(head->nxt);
}

template<typename T>
typename List<T>::iterator List<T>::end()
{
    return iterator(tail);
}

上述代码中,利用 Node<T> 类来定义节点的数据类型,同时 List 类中包含了一个头结点和一个尾节点,并实现了常用的操作函数。注意到 List 中包含了指向节点的指针,并通过构造函数、拷贝构造函数、析构函数和赋值运算符进行了初始化和清理。此外,注意到 List 中自己实现了 push_frontpush_backinserterase 等操作函数,这些操作函数都需要首先进行节点的内存分配操作。

示例说明

示例1:List的基本操作

下面是使用 List 容器的一个示例,演示了基本的遍历和修改操作:

#include <iostream>
#include "List.h"

using namespace std;

int main()
{
    List<int> l1;
    for(int i=0; i<10; ++i)
        l1.push_back(i);

    cout << "l1 = ";
    for(auto it=l1.begin(); it!=l1.end(); ++it)
        cout << *it << " ";
    cout << endl;

    List<int> l2(l1);
    cout << "l2 = ";
    for(auto it=l2.begin(); it!=l2.end(); ++it)
        cout << *it << " ";
    cout << endl;

    for(auto it=l1.begin(); it!=l1.end(); ++it)
        *it = 2*(*it);

    cout << "l1 = ";
    for(auto it=l1.begin(); it!=l1.end(); ++it)
        cout << *it << " ";
    cout << endl;

    l2.clear();
    cout << "l2 is " << (l2.empty() ? "empty" : "not empty") << endl;

    return 0;
}

代码中,使用了 List 的常用操作,包括构造函数、迭代器、遍历和修改等。其中第一行使用了 List 的默认构造函数,并依次调用 push_back 函数插入元素。输出结果如下:

l1 = 0 1 2 3 4 5 6 7 8 9
l2 = 0 1 2 3 4 5 6 7 8 9
l1 = 0 2 4 6 8 10 12 14 16 18
l2 is empty

可以看到,随着 List 中元素的插入、遍历和修改,输出的结果一直在变化,而所有的操作都是通过自定义的迭代器实现的。

示例2:List的排序操作

下面是使用 List 容器的第二个示例,演示了排序操作:

#include <iostream>
#include "List.h"

using namespace std;

int main()
{
    List<int> l;
    for(int i=0; i<10; ++i)
        l.push_back(rand()%100);

    cout << "List:";
    for(auto it=l.begin(); it!=l.end(); ++it)
        cout << " " << *it;
    cout << endl;

    l.sort();
    cout << "Sorted list:";
    for(auto it=l.begin(); it!=l.end(); ++it)
        cout << " " << *it;
    cout << endl;

    return 0;
}

代码中,通过 List::sort 函数对 List 进行排序,并输出排序结果。注意到,由于 List 是一个双向链表,所以排序操作使用了 std::list 的算法来实现。输出结果如下:

List: 45 50 14 64 73 42 93 0 61 72
Sorted list: 0 14 42 45 50 61 64 72 73 93

可以看到, List::sort 函数可以对罗列数据进行排序。其中的排序算法是基于 std::list 的算法实现的,具有较高的效率和良好的可维护性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++模拟实现List迭代器详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 基于Python函数和变量名解析

    基于Python函数和变量名解析的完整攻略 Python是一种动态类型的编程语言,它允许我们在运行时根据需要创建和修改函数和变量。这种灵活性使得Python函数和变量名解析成为一项重要的特性。在本攻略中,我们将详细讲解Python函数和变量名解析的过程和示例。 函数名解析 在Python中,函数名是一个标识符,用于引用函数对象。函数名解析是指Python解释…

    other 2023年7月29日
    00
  • oracle创建数据表以及对数据表、字段、主外键、约束的操作

    Oracle创建数据表以及对数据表、字段、主外键、约束的操作的完整攻略 在Oracle数据库中,创建数据表以及对数据表、字段、主外键、约束的操作是非常常见的操作。本文将提供Oracle创建数据表以及对数据表、字段、主外键、约束的操作的完整攻略,包括以下步骤: 创建数据表 修改数据表 删除数据表 添加字段 修改字段 删除字段 添加主键 添加外键 添加约束 示例…

    other 2023年5月9日
    00
  • 星外虚拟主机管理平台 3.5重要更新说明

    星外虚拟主机管理平台3.5重要更新说明 本次更新主要更新了星外虚拟主机管理平台的许多功能和优化了用户体验,以下是本次更新的详细内容。 功能更新 新增模板管理功能 新增加了模板管理功能,即可以自定义网站模板,在线编辑代码。 使用方法:登录星外虚拟主机管理平台后,在左侧导航栏的“网站管理”菜单下,选择“模板管理”,即可进入模板管理页面。在此页面,您可以选择现有模…

    other 2023年6月27日
    00
  • 浅谈数据库日期类型字段设计应该如何选择

    当我们设计数据库时,日期类型字段是一个必不可少的部分。但是,在选择日期类型字段时,我们应该考虑哪些因素?本篇攻略就会详细的讲解如何选择日期类型字段的设计。 选项 在SQL数据库中,通常有三种类型的日期字段: 日期类型(DATE):仅存储年、月和日期. 时间类型(TIME):仅存储小时、分钟和秒 时间戳类型(DATETIME或TIMESTAMP):存储日期和时…

    other 2023年6月25日
    00
  • Java数据结构实现二维数组与稀疏数组转换详解

    Java数据结构实现二维数组与稀疏数组转换详解 一、二维数组与稀疏数组 在介绍二维数组与稀疏数组的转换之前,需要先了解它们的定义和特点。 1.二维数组 二维数组是一个由多个一维数组组成的数组。可以将它理解为是一个由行和列构成的矩阵。其中,行和列的数量是固定的,而且必须预先指定。 二维数组的声明方式为: 数据类型[][] 数组名; 例: int[][] arr…

    other 2023年6月27日
    00
  • 服务器授权模式每服务器同时连接数与每设备或每用户的区别小结

    服务器授权模式是指在服务器端限制客户端连接的数量,可以分为每服务器同时连接数和每设备或每用户连接数两种模式。它们的区别如下: 每服务器同时连接数 每服务器同时连接数是指在一个服务器上限制客户端的连接数量。在此模式下,对于同一IP地址的所有设备或用户,如果它们发起的连接数超过了限制,就会被服务器拒绝连接。每服务器同时连接数适用于需要限制客户端总连接数的场景,如…

    other 2023年6月27日
    00
  • Excel怎么制作带有多个Excel图表控件的动态图表?

    制作带有多个Excel图表控件的动态图表,可以通过以下步骤实现: 1. 前期准备 首先,需要准备好数据源。在Excel中创建一个包含多个数据系列的数据表格,确保每一列的数据可以映射到不同的图表控件上。 2. 创建图表控件 在Excel中,选择“插入”选项卡,在“图表”组中选择需要的图表类型,然后插入一个新的图表。此时,Excel会自动创建一个空白图表,并在工…

    other 2023年6月27日
    00
  • java实现文件上传到linux服务器中

    以下是关于“Java实现文件上传到Linux服务器中”的完整攻略,过程中包含两个示例。 背景 在Java开发中,有时需要将文件上传到Linux服务器中。本攻略将介绍如何使用Java实现文件上传到Linux服务器中。 基本原理 Java实现文件上传到Linux服务器的基本原理是通过SSH协议连接到Linux服务器,然后使用SCP命令将文件上传到服务器中。具体步…

    other 2023年5月9日
    00
合作推广
合作推广
分享本页
返回顶部