链表迭代器实现C++

Linked List Iterator Implementation C++

本文关键字:C++ 实现 迭代器 链表      更新时间:2023-10-16

我在C++中创建了一个链表,并希望为它实现一个迭代器,以便我可以执行范围循环:for (const int& i : list)Linked_List<int> list;的位置。

我的想法是将Iterator创建为Linked_List类的一部分,如下所示:

这是我到目前为止得到的:

template <typename T>
class Linked_List
{
public:
struct Iterator;
struct Node;
public:
Linked_List();
~Linked_List() noexcept(false);
Linked_List(const Linked_List&) = delete;
Linked_List(Linked_List&&) = delete;
Linked_List& operator=(const Linked_List&) = delete;
Linked_List& operator=(Linked_List&&) = delete;
void push_back(T);
void push_front(T);
void pop_back();
void pop_front();
bool empty() const;
T back() const;
T front() const;
//void swap(T, T);
//void insert(Iterator, T);
//void erase(Iterator);
//Iterator begin() const;
//Iterator end() const;
private:
Node* head;
Node* tail;
};
template<typename T>
struct Linked_List<T>::Node
{
Node() : prev(nullptr), next(nullptr) {}
Node(T t) : value(t), prev(nullptr), next(nullptr) {}
Node* prev;
Node* next;
T value;
};
  1. 这是一个好方法吗?
  2. 我应该在递增列表时进行错误检查以检查是否current->next == tail?如果是这样,我该怎么做?因为我的迭代器没有带尾巴的列表对象。

编辑: 我不确定如何实现struct Iterator;,在弄清楚如何将其与列表连接时,我陷入了困境,以便我可以检查从迭代器返回的当前节点是否等于列表中的尾部,在 Linked_ListIterator end() const方法中。

假设我已经为这样的迭代器实现了所有必要的运算符:

struct Iterator
{
T& operator*() const { return current->value; }
bool operator!=(const Iterator& rhs) { return (*_current != rhs._current); }
Iterator& operator++()
{
current = current->next;
return *this;
}
};

我现在该如何实施Iterator Linked_List<T>::begin() const;end()

我想象一个虚构的用户制作一个迭代器对象,如下所示:Linked_List<int>::Iterator it;

一个想法是拥有一个没有参数的公共构造函数和一个将节点作为_current将要设置为的参数的私有构造函数,并将Linked_List类作为友元。

一些注意事项。

有两个选项可以声明NodeIterator。列表类内部为List<T>::Node或外部为Node<T>。这在一定程度上是一个品味问题。但是,从工程角度来看,嵌套类的符号名称更长,因此调试信息更大。此外,当嵌套类也是模板时,在必要时很难专门化它们(因为这需要首先完全专用封闭模板),但这里的情况并非如此。

当一个列表节点用作列表头和尾时,它会导致更优雅的代码。空列表是一个节点,其nextprev指向自身。push_front追加到指向第一个节点或自身的list.nextpush_back将节点追加到指向最后一个节点或自身的list.prev。插入/删除节点时,无需对第一个和最后一个节点进行特殊处理。例如:

struct Node {
Node *next_, *prev_;
Node() 
: next_(this), prev_(this)
{}
~Node() { 
unlink();
}
void push_back(Node* n) {
n->next_ = this;
n->prev_ = prev_;
prev_->next_ = n;
prev_ = n;
}
void unlink() {
Node *next = next_, *prev = prev_;
next->prev_ = prev;
prev->next_ = next;
next_ = this;
prev_ = this;
}
};

在上面,Node只需要两个操作就可以维护一个列表。不仅如此,Node本身就是一个极简主义列表,可用于侵入性列表(在析构函数中具有自动取消链接)。请注意,使用this如何使检查nullptr变得不必要 -Node始终是有效的列表。

错误检查应仅处于调试模式(例如,使用assert)。否则,这些检查会使用不必要的运行时检查来惩罚正确的应用程序。


这是一个基于您的想法的最小工作示例:

template<class T>
class List;
class Iterator;
class Node {
friend class Iterator;
template<class T> friend class List;
protected:
Node *next_, *prev_;
void push_back(Node* n) {
n->next_ = this;
n->prev_ = prev_;
prev_->next_ = n;
prev_ = n;
}
void unlink() {
Node *next = next_, *prev = prev_;
next->prev_ = prev;
prev->next_ = next;
next_ = this;
prev_ = this;
}
public:
Node()
: next_(this), prev_(this)
{}
~Node() { unlink(); }
};
class Iterator {
protected:
Node* node_;
Iterator(Node* node)
: node_(node)
{}
public:
Iterator& operator++() {
node_ = node_->next_;
return *this;
}
bool operator==(Iterator b) const { return node_ == b.node_; }
bool operator!=(Iterator b) const { return node_ != b.node_; }
// Implement the rest of iterator interface.
};
template<class T>
class List {
class NodeT : public Node {
friend class List<T>;
T value_;
NodeT(T t) : value_(t) {}
};
template<class U>
class IteratorT : public Iterator {
friend class List<T>;
NodeT* node() const { return static_cast<NodeT*>(node_); }
public:
U& operator*() const { return node()->value_; }
U* operator->() const { return &node()->value_; }
operator IteratorT<U const>() const { return node_; } // iterator to const_iterator conversion
IteratorT(Node* node) : Iterator{node} {}
};
Node list_;
public:
using iterator = IteratorT<T>;
using const_iterator = IteratorT<T const>;
~List() { clear(); }
bool empty() const { return list_.next_ == &list_; }
iterator begin() { return list_.next_; }
iterator end() { return &list_; }
void push_back(T t) { list_.push_back(new NodeT(t)); }
void erase(const_iterator i) { delete i.node(); }
void clear() {
while(!empty())
erase(begin());
}
// Implement the rest of the functionality.
};
int main() {
List<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
for(auto elem : l)
std::cout << elem << ' ';
std::cout << 'n';
}