0
点赞
收藏
分享

微信扫一扫

为单链表实现一个迭代器

杨小羊_ba17 2022-02-13 阅读 70
c++

文章目录

迭代器概念

迭代器是一种抽象的设计概念,程序设计语言中并没有与之对应的实物。《设计模式》中对迭代器模式的定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式

STL的中心思想是:将数据容器算法分开,彼此独立设计,最后再使用胶着剂把他们撮合在一起(迭代器扮演胶着剂)。如Find函数通过迭代器访问容器内的数据,而不关心数据是如何表示的。

#include <vector>
#include <list>
#include <iostream>

template <typename InputIterator, class T>
InputIterator Find(InputIterator first, InputIterator last, const T &value)
{
    while (first != last && *first != value) {
        ++first;
    }
    return first;
}

int main()
{
    std::vector<int> vi = {1, 2, 3, 4, 5};
    std::list<int> li = {1, 2, 3, 4, 5};

    auto it1 = Find(vi.begin(), vi.end(), 3);
    if (it1 != vi.end()) {
        std::cout << "found 3" << std::endl;
    }

    auto it2 = Find(li.begin(), li.end(), 3);
    if (it1 != vi.end()) {
        std::cout << "found 3" << std::endl;
    }

    return 0;
}

在这里插入图片描述

迭代器和指针

迭代器是一种行为类似于指针的对象,是对指针的封装,因此它最重要的编程工作就是重载operator*operator->,当然有时还得重载operator++operator==operator!=等。

单链表的迭代器

为了不向外暴露过多细节,每一种STL容器都提供有自己专属的迭代器

实现

class Node { // 节点
public:
    Node() : next_(nullptr) {}
    Node(const Item &item) : item_(item), next_(nullptr) {}
    Item item_;
    Node *next_;
};

class Iterator { // 指向节点的迭代器
public:
    Iterator(Node *ptr = nullptr) : ptr_(ptr) {};
    Item &operator*() const
    {
        return ptr_->item_;
    }
    Item *operator->() const
    {
        return &ptr_->item_;
    }
    Iterator &operator++()   // 前置加
    {
        ptr_ = ptr_->next_;
        return *this;
    }
    Iterator operator++(int) // 后置加
    {
        auto tmp = *this;
        ++this; // 调用前置加
        return tmp;
    }
    bool operator==(const Iterator &rhs)
    {
        return ptr_ == rhs.ptr_;
    }
    bool operator!=(const Iterator &rhs)
    {
        return ptr_ != rhs.ptr_;
    }
    Node *ptr_;
};

虽然ptr_指向的是一个Node,但对迭代器执行解引用操作时,返回的是Nodeitem_成员,因为外界关注的是单链表保存的数据
注意前置加后置加的区别。

Iterator it;
++it; // 前置加
it++; // 后置加

比较两个迭代器的时候,看的是它们内部的指针是否指向同一个Node

NodeIterator都嵌入到单链表类中,完整的代码如下:
slist.h

#ifndef SLIST_H
#define SLIST_H

#include <cstddef>

template <typename Item>
class SList {
    class Node { // 节点
    public:
        Node() : next_(nullptr) {}
        Node(const Item &item) : item_(item), next_(nullptr) {}
        Item item_;
        Node *next_;
    };

    class Iterator { // 指向节点的迭代器
    public:
        Iterator(Node *ptr = nullptr) : ptr_(ptr) {};
        Item &operator*() const
        {
            return ptr_->item_;
        }
        Item *operator->() const
        {
            return &ptr_->item_;
        }
        Iterator &operator++()   // 前置加
        {
            ptr_ = ptr_->next_;
            return *this;
        }
        Iterator operator++(int) // 后置加
        {
            auto tmp = *this;
            ++this; // 调用前置加
            return tmp;
        }
        bool operator==(const Iterator &rhs)
        {
            return ptr_ == rhs.ptr_;
        }
        bool operator!=(const Iterator &rhs)
        {
            return ptr_ != rhs.ptr_;
        }
        Node *ptr_;
    };

public:
    SList();
    ~SList();
    void PushFront(const Item &item); // 在链表头插入节点
    void PushBack(const Item &item);  // 在链表尾插入节点
    Item PopFront();                  // 从链表头删除节点
    bool IsEmpty() const;
    size_t Size() const;
    Iterator begin() const;
    Iterator end() const;

private:
    Node *first_;
    Node *last_;
    size_t N_;
};

template <typename Item>
SList<Item>::SList()
{
    first_ = new Node();
    last_ = first_;
    N_ = 0;
}

template <typename Item>
SList<Item>::~SList()
{
    last_ = nullptr;
    while (N_--)
    {
        Node *next = first_->next_;
        delete first_;
        first_ = next;
    }
}

template <typename Item>
void SList<Item>::PushFront(const Item &item)
{
    if (first_ == last_) {
        PushBack(item);
        return;
    }

    Node *cur = new Node(item);
    Node *next = first_->next_;
    cur->next_ = next;
    first_->next_ = cur;
    ++N_;
}

template <typename Item>
void SList<Item>::PushBack(const Item &item)
{
    Node *cur = new Node(item);
    last_->next_ = cur;
    last_ = cur;
    ++N_;
}

template <typename Item>
Item SList<Item>::PopFront()
{
    if (first_ == last_) {
        return {};
    }

    Node *cur = first_->next_;
    Node *next = cur->next_;
    first_->next_ = next;
    Item item = cur->item_;
    delete cur;
    --N_;

    if (!next) {
        last_ = first_;
    }

    return item;
}

template <typename Item>
bool SList<Item>::IsEmpty() const
{
    return !N_;
}

template <typename Item>
size_t SList<Item>::Size() const
{
    return N_;
}

template <typename Item>
typename SList<Item>::Iterator SList<Item>::begin() const
{
    return Iterator(first_->next_);
}

template <typename Item>
typename SList<Item>::Iterator SList<Item>::end() const
{
    return Iterator(last_->next_);
}

#endif

有了迭代器beginend成员,就可以使用范围for循环遍历单链表了。

测试

main.cpp

#include <string>
#include <iostream>
#include "slist.h"

int main()
{
    SList<std::string> sstr;
    sstr.PushBack("hello");
    sstr.PushBack("world");
    sstr.PushBack("china");
    sstr.PushFront("one");
    sstr.PushFront("two");
    sstr.PushFront("three");

    for (const auto &ele : sstr) {
        std::cout << ele << std::endl;
    }

    return 0;
}

运行:
在这里插入图片描述

举报

相关推荐

0 条评论