文章目录
迭代器概念
迭代器是一种抽象的设计概念,程序设计语言中并没有与之对应的实物。《设计模式》中对迭代器模式的定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式。
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
,但对迭代器执行解引用操作时,返回的是Node
的item_
成员,因为外界关注的是单链表保存的数据。
注意前置加和后置加的区别。
Iterator it;
++it; // 前置加
it++; // 后置加
比较两个迭代器的时候,看的是它们内部的指针是否指向同一个Node
。
把Node
和Iterator
都嵌入到单链表类中,完整的代码如下:
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
有了迭代器和begin
、end
成员,就可以使用范围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;
}
运行: