数据结构基础(10) --单链表迭代器的设计与实现

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
简介: 为了向 STL 致敬(O(∩_∩)O~), 我们模仿STL中的list的迭代器, 我们也自己实现一个MyList的迭代器, 以供遍历整个链表的所有元素:首先:Node节点需要做如下修改(注意...

为了向 STL 致敬(O(∩_∩)O~), 我们模仿STL中的list的迭代器, 我们也自己实现一个MyList的迭代器, 以供遍历整个链表的所有元素:

首先:Node节点需要做如下修改(注意后缀有+的代码)

//链表节点
template <typename Type>
class Node
{
    friend class MyList<Type>;
    friend class ListIterator<Type>;	//+

    template <typename T>
    friend ostream &operator<<(ostream &os, const MyList<T> &list);
private:
    Node(const Type &dataValue):data(dataValue), next(NULL) {}

    Type data;  //数据域:节点数据
    Node *next; //指针域:下一个节点
};

然后:MyList类同样也需要做修改,但是由于MyList类过长修改之处也较少因此在此就不贴出完整代码会附到博客最后

 

ListIterator的设计

template <typename Type>
class ListIterator
{
public:
    ListIterator(const MyList<Type> &_list):
        list(_list),
        currentNode((_list.first)->next) {}

    //重载 *operator
    const Type &operator*() const throw (std::out_of_range);
    Type &operator*() throw (std::out_of_range);

    //重载 ->operator
    const Node<Type> *operator->() const throw (std::out_of_range);
    Node<Type> *operator->() throw (std::out_of_range);

    //重载 ++operator
    ListIterator &operator++() throw (std::out_of_range);
    //注意:此处返回的是值,而不是reference
    ListIterator operator++(int) throw (std::out_of_range);

    bool isEmpty() const;

private:
    const MyList<Type> &list;
    Node<Type> *currentNode;
};

ListIterator类的实现

template <typename Type>
const Type &ListIterator<Type>::operator*() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    // 返回当前指针指向的内容
    return currentNode->data;
}

template <typename Type>
Type &ListIterator<Type>::operator*()
throw (std::out_of_range)
{
    //首先为*this添加const属性,
    //以调用该函数的const版本,
    //然后再使用const_case,
    //将该函数调用所带有的const属性转除
    //operator->()的non-const版本与此类同
    return
        const_cast<Type &>(
            static_cast<const ListIterator<Type> &>(*this).operator*()
        );
}

template <typename Type>
const Node<Type> *ListIterator<Type>::operator->() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //直接返回指针
    return currentNode;
}

template <typename Type>
Node<Type> *ListIterator<Type>::operator->()
throw (std::out_of_range)
{
    // 见上
    return
        const_cast<Node<Type> *> (
            static_cast<const ListIterator<Type> >(*this).operator->()
        );
}

template <typename Type>
ListIterator<Type> &ListIterator<Type>::operator++()
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //指针后移
    currentNode = currentNode->next;
    return *this;
}
template <typename Type>
ListIterator<Type> ListIterator<Type>::operator++(int)
throw (std::out_of_range)
{
    ListIterator tmp(*this);
    ++ (*this); //调用前向++版本

    return tmp;
}

//判空
template <typename Type>
bool ListIterator<Type>::isEmpty() const
{
    if (currentNode == NULL)
        return true;
    return false;
}

-ListIterator测试代码:

int main()
{
    std::list<int> iStdList;
    MyList<int>    iMyList;
    for (int i = 0; i < 10; ++i)
    {
        iStdList.push_back(i+1);
        iMyList.insert(i+1, i+1);
    }

    for (std::list<int>::iterator iter = iStdList.begin();
            iter != iStdList.end();
            ++ iter)
    {
        cout << *iter << ' ';
    }
    cout << endl;

    for (ListIterator<int> iter(iMyList);
            !iter.isEmpty();
            ++ iter)
    {
        cout << *iter << ' ';
    }
    cout << endl;

    cout << "Test: \n\t" << iMyList << endl;


    ListIterator<int> iter(iMyList);
cout << "first = " << *iter << endl;
}


附-MyList完整源代码

//MyList.h
#ifndef MYLIST_H_INCLUDED
#define MYLIST_H_INCLUDED

#include <iostream>
#include <stdexcept>
using namespace std;

//前向声明
template <typename Type>
class MyList;
template <typename Type>
class ListIterator;

//链表节点
template <typename Type>
class Node
{
    //可以将MyList类作为Node的友元
    //同时也可以将Node类做成MyList的嵌套类, 嵌套在MyList中, 也可以完成该功能
    friend class MyList<Type>;
    friend class ListIterator<Type>;

    template <typename T>
    friend ostream &operator<<(ostream &os, const MyList<T> &list);
private:
    //constructor说明:
    //next = NULL;    //因为这是一个新生成的节点, 因此下一个节点为空
    Node(const Type &dataValue):data(dataValue), next(NULL) {}

    Type data;  //数据域:节点数据
    Node *next; //指针域:下一个节点
};

//链表
template <typename Type>
class MyList
{
    template <typename T>
    friend ostream &operator<<(ostream &os, const MyList<T> &list);

    friend class ListIterator<Type>;
public:
    MyList();
    ~MyList();

    //将元素插入表头
    void insertFront(const Type &data);
    //将元素插入到位置index上(index从1开始)
    void insert(const Type &data, int index);
    //删除表中所有值为data的节点
    void remove(const Type &data);
    bool isEmpty() const;

    //链表反转
    void invort();
    //将链表(list)链接到本条链表的末尾
    void concatenate(const MyList<Type> &list);

private:
    //指向第一个节点的指针
    Node<Type> *first;
};

template <typename Type>
MyList<Type>::MyList()
{
    //first指向一个空节点
    first = new Node<Type>(0);
    first -> next = NULL;
}
template <typename Type>
MyList<Type>::~MyList()
{
    Node<Type> *deleteNode = NULL;
    while (first != NULL)
    {
        deleteNode = first;
        first = first -> next;
        delete deleteNode;
    }
}

template <typename Type>
void MyList<Type>::insertFront(const Type &data)
{
    Node<Type> *newNode = new Node<Type>(data);
    newNode -> next = first -> next;
    first -> next = newNode;
}

template <typename Type>
void MyList<Type>::insert(const Type &data, int index)
{
    //由于我们在表头添加了一个空节点
    //因此如果链表为空, 或者在链表为1的位置添加元素
    //其操作与在其他位置添加元素相同

    int count = 1;
    //此时searchNode肯定不为NULL
    Node<Type> *searchNode = first;
    // 找到要插入的位置
    // 如果所给index过大(超过了链表的长度)
    // 则将该元素插入到链表表尾
    // 原因是 searchNode->next != NULL 这个条件已经不满足了
    // 已经到达表尾
    while (count < index && searchNode->next != NULL)
    {
        ++ count;
        searchNode = searchNode->next;
    }

    // 插入链表
    Node<Type> *newNode = new Node<Type>(data);
    newNode->next = searchNode->next;
    searchNode->next = newNode;
}

template <typename Type>
void MyList<Type>::remove(const Type &data)
{
    if (isEmpty())
        return ;

    Node<Type> *previous = first;   //保存要删除节点的前一个节点
    for (Node<Type> *searchNode = first->next;
            searchNode != NULL;
            searchNode = searchNode->next)
    {
        if (searchNode->data == data)
        {
            previous->next = searchNode->next;
            delete searchNode;
            //重新调整searchNode指针
            //继续遍历链表查看是否还有相等元素

            //如果当前searchNode已经到达了最后一个节点
            //也就是searchNode->next已经等于NULL了, 则下面这条语句不能执行
            if (previous->next == NULL)
                break;

            searchNode = previous->next;
        }
        previous = searchNode;
    }
}
template <typename Type>
bool MyList<Type>::isEmpty() const
{
    return first->next == NULL;
}

template <typename Type>
void MyList<Type>::concatenate(const MyList<Type> &list)
{
    if (isEmpty())//如果自己的链表为空
    {
        first = list.first;
        return ;
    }
    else if (list.isEmpty())    //如果第二条链表为空
    {
        return ;
    }

    Node<Type> *endNode = first->next;
    //找到第一条链表的末尾节点
    while (endNode->next != NULL)
    {
        endNode = endNode->next;
    }

    //找到第二条链表的第一个真实元素
    Node<Type> *secondListNode = (list.first)->next;
    //注意: 需要将第二个链表中的元素值copy出来
    //不能直接将第二条链表的表头链接到第一条链表的表尾
    //不然在析构函数回收内存时会发生错误(即:同一段内存释放两次)
    while (secondListNode != NULL)
    {
        Node<Type> *newNode = new Node<Type>(secondListNode->data);
        newNode->next = NULL;
        endNode->next = newNode;

        //两条链表同时前进
        endNode = endNode->next;
        secondListNode = secondListNode->next;
    }
}

template <typename Type>
void MyList<Type>::invort()
{
    if (!isEmpty())
    {
        //p指向正向链表的第一个真实节点
        //随后, p也会沿正方向遍历到链表末尾
        Node<Type> *p = first->next;

        //q会成为倒向的第一个真实节点
        //首先将q设置为NULL: 保证反向之后
        //最后一个元素的指针域指向NULL, 以表示链表结束
        Node<Type> *q = NULL;
        while (p != NULL)
        {
            Node<Type> *r = q;  //暂存q当前指向的节点
            //q后退(沿着正向后退)
            q = p;
            //p前进(沿着正向前进), 保证p能够始终领先q一个位置
            p = p -> next;
            //将指针逆向反转
            //注意:一点要保证这条语句在p指针移动之后运行,
            //不然p就走不了了...(因为q改变了指针的朝向)
            q -> next = r;
        }

        //此时q成为反向链表的第一个真实元素
        //但是为了维护像以前一样的first指针指向一个无用的节点(以使前面的操作不会出错)
        //于是我们需要将first的指针域指向q
        first->next = q;
    }
}

//显示链表中的所有数据(测试用)
template <typename Type>
ostream &operator<<(ostream &os, const MyList<Type> &list)
{
    for (Node<Type> *searchNode = list.first -> next;
            searchNode != NULL;
            searchNode = searchNode -> next)
    {
        os << searchNode -> data;
        if (searchNode -> next != NULL) //尚未达到链表的结尾
            cout << " -> ";
    }

    return os;
}

//ListIterator的设计与实现
template <typename Type>
class ListIterator
{
public:
    ListIterator(const MyList<Type> &_list):
        list(_list),
        currentNode((_list.first)->next) {}

    //重载 *operator
    const Type &operator*() const throw (std::out_of_range);
    Type &operator*() throw (std::out_of_range);

    //重载 ->operator
    const Node<Type> *operator->() const throw (std::out_of_range);
    Node<Type> *operator->() throw (std::out_of_range);

    //重载 ++operator
    ListIterator &operator++() throw (std::out_of_range);
    //注意:此处返回的是值,而不是reference
    ListIterator operator++(int) throw (std::out_of_range);

    bool isEmpty() const;

private:
    const MyList<Type> &list;
    Node<Type> *currentNode;
};

template <typename Type>
const Type &ListIterator<Type>::operator*() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    // 返回当前指针指向的内容
    return currentNode->data;
}
template <typename Type>
Type &ListIterator<Type>::operator*()
throw (std::out_of_range)
{
    //首先为*this添加const属性,
    //以调用该函数的const版本,
    //然后再使用const_case,
    //将该函数调用所带有的const属性转除
    //operator->()的non-const版本与此类同
    return
        const_cast<Type &>(
            static_cast<const ListIterator<Type> &>(*this).operator*()
        );
}

template <typename Type>
const Node<Type> *ListIterator<Type>::operator->() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //直接返回指针
    return currentNode;
}

template <typename Type>
Node<Type> *ListIterator<Type>::operator->()
throw (std::out_of_range)
{
    // 见上
    return
        const_cast<Node<Type> *> (
            static_cast<const ListIterator<Type> >(*this).operator->()
        );
}

template <typename Type>
ListIterator<Type> &ListIterator<Type>::operator++()
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //指针前移
    currentNode = currentNode->next;
    return *this;
}
template <typename Type>
ListIterator<Type> ListIterator<Type>::operator++(int)
throw (std::out_of_range)
{
    ListIterator tmp(*this);
    ++ (*this); //调用前向++版本

    return tmp;
}
template <typename Type>
bool ListIterator<Type>::isEmpty() const
{
    if (currentNode == NULL)
        return true;
    return false;
}

#endif // MYLIST_H_INCLUDED

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
46 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
2月前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
26 1
|
3月前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
2月前
|
存储
【数据结构】——单链表实现
【数据结构】——单链表实现
|
2月前
|
存储
数据结构2——单链表
数据结构2——单链表
39 1
|
2月前
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
2月前
|
存储
数据结构(单链表)
数据结构(单链表)
21 0
|
2月前
|
存储
数据结构--单链表
数据结构--单链表
|
3月前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
678 6
|
2月前
|
存储 缓存
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(二)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)