【问题标题】:Overloading the dereference operator for a custom iterator为自定义迭代器重载取消引用运算符
【发布时间】:2013-12-17 00:02:33
【问题描述】:

这是我第一次使用迭代器,因此可能存在严重错误。我正在尝试制作一个有序的迭代迭代器类来与我的线程二叉搜索树一起工作。所以迭代器正在节点上工作。我只需要迭代器依次遍历我的树,这样我就可以打印每个节点的所有值和频率。但是,我的取消引用似乎不起作用。这是给我带来麻烦的方法:

//-------------------------- inOrderTraverse ------------------------------------
template <typename T>
void ThreadedBST<T>::inOrderTraverse() {
    InorderIterator<T>* iter = new InorderIterator<T>(root);
    ++iter;

    while ((*iter) != NULL)
    {
        cout << (*iter)->getItem() << " " << (*iter)->getFrequency() << endl;
    }
}

特别是 while 循环会引发编译器错误。这是确切的错误:

错误 C2678:二进制“!=”:未找到采用“InorderIterator”类型的左侧操作数的运算符

我认为取消引用会将节点带出,所以我实际上是在比较节点!= NULL 但这不是错误消息让我相信的。这是完整的迭代器类:

#ifndef INORDERITER_H
#define INORDERITER_H

#include <iostream>
#include "ThreadedBST.h"
using namespace std;

//---------------------------------------------------------------------------
// InorderIterator<T> class: 
//   -- 
//
// Assumptions:
//   -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------

template <typename T>
class InorderIterator {

public:
    InorderIterator(node<T> *); //constructor
    InorderIterator<T>& operator++();
    node<T>& operator*();
    const node<T>& operator*() const;

private:
    node<T>* begin;
    node<T>* curr;
    node<T>* prev;
    node<T>* temp;
};

template <typename T>
InorderIterator<T>::InorderIterator(node<T>* root) {
    begin = root;
    temp = NULL;

    while (begin->leftChild != NULL) {
        begin = begin->leftChild;
    }
}

template <typename T>
InorderIterator<T>& InorderIterator<T>::operator++() {
    if (temp == NULL)
        temp = begin;
    else if (rightChildThread) {
        prev = temp;
        temp = temp->rightChild;
    }
    else {
        prev = temp;
        temp = temp->rightChild;

        while (!temp->rightChildThread && (temp->leftChild->getItem() != prev->getItem())) {
            temp = temp->leftChild;
        }
    }

    curr = temp;
    return *this;
}

template <typename T>
node<T>& InorderIterator<T>::operator*() {
    return *curr;
}

template <typename T>
const node<T>& InorderIterator<T>::operator*() const {
    return *curr;
}

#endif

如果出于任何原因相关,这里是节点类:

#ifndef NODE_H
#define NODE_H

#include <iostream>
using namespace std;

//---------------------------------------------------------------------------
// node<T> class: 
//   -- 
//
// Assumptions:
//   -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------

template <typename T>
class node {

public:
    node<T>* leftChild;
    node<T>* rightChild;
    bool leftChildThread;
    bool rightChildThread;
    node(T value); //constructor
    node(T value, node<T>*, node<T>*, bool, bool); //secondary constructor
    node(const node<T>&); //copy constructor
    void decrementFrequency(); //decrements by 1 the frequency
    void incrementFrequency(); //increments by 1 the frequency
    int getFrequency(); //returns the frequency
    T getItem(); //returns the item

private:
    T item;
    int frequency;
};

//-------------------------- Constructor ------------------------------------
template <typename T>
node<T>::node(T value) {
    item = value;
    frequency = 1;

}

//-------------------------- Secondary Constructor ------------------------------------
template <typename T>
node<T>::node(T value, node<T>* left, node<T>* right, bool leftThread, bool rightThread) {
    item = value;
    frequency = 1;
    leftChild = left;
    rightChild = right;
    leftChildThread = leftThread;
    rightChildThread = rightThread;
}

//-------------------------- Copy ------------------------------------
template <typename T>
node<T>::node(const node<T>& copyThis) {
    item = copyThis.value;
    frequency = copyThis.frequency;
}

//-------------------------- decrementFrequency ------------------------------------
template <typename T>
void node<T>::decrementFrequency() {
    frequency--;
}

//-------------------------- incrementFrequency ------------------------------------
template <typename T>
void node<T>::incrementFrequency() {
    frequency++;
}

//-------------------------- getFrequency ------------------------------------
template <typename T>
int node<T>::getFrequency() {
    return frequency;
}

//-------------------------- getItem ------------------------------------
template <typename T>
T node<T>::getItem() {
    return item;
}

#endif

【问题讨论】:

  • InorderIterator&lt;T&gt;* iter = new InorderIterator&lt;T&gt;(root); 声明了一个指向迭代器的指针,并动态分配迭代器。你想要:InorderIterator&lt;T&gt; iter(root);。 (您是否将 Java 的 new 与 C++ 的 new 混淆了?)
  • 很可能。感谢您的帮助。现在似乎可以正确取消引用,我只需要自己解决其他错误。关于如何遍历所有节点的任何建议?我不确定我是否理解迭代器如何知道它何时完成(或者我可能没有实现该功能)?那个while循环似乎不是正确的方法。
  • @MilanNovaković 在下面看到我的答案

标签: c++ iterator operator-overloading dereference


【解决方案1】:
  class const_iterator {
    public:
        Node *current;

        const_iterator (Node *n) : current{n}
        {
            /* the body can remain blank, the initialization is carried
             * the the constructor init list above
             */
        }

        /* copy assignment */
        const_iterator operator= (const const_iterator& rhs) {
            this->current = rhs.current;
            return *this;
        }

        bool operator == (const const_iterator& rhs) const {
            return this->current == rhs.current;
        }
        bool operator != (const const_iterator& rhs) const {
            return this->current != rhs.current;
        }

        /* Update the current pointer to advance to the node
         * with the next larger value
         */
        const_iterator& operator++ () {
            /*first step is to go left as far as possible(taken care of by begin())
             once you go as left as possible, go right one step at a time*/
            if(current->right != nullptr){
                current = current->right;
                //every step, go left again as far as possible
                while(current->left != nullptr){
                    current = current->left;
                }
            }else{
                bool upFromLeft = false;
                bool upFromRight = false;
                while(upFromLeft == false && upFromRight == false){
                    //if you have gone all the way up from the right
                    if(current->parent == nullptr){
                        upFromRight = true;
                        current = current->parent;
                        return *this;
                    }
                    //if you have gone all the way back up left
                    if(current->parent->left == current){
                        upFromLeft = true;
                        current = current->parent;
                        return *this;
                    }
                    current = current->parent;
                }
            }
            return *this;
        }

        Z& operator *() const {
            return current->data;
        }
    };

将这些函数添加到您的树中,以便将 begin() 和 end() 与您的迭代器一起使用

        const const_iterator begin() const {
        if(rootPtr == nullptr){
            return nullptr;
        }
        Node* temp = rootPtr;
        while(temp->left != nullptr){
            temp = temp->left;
        }
        return const_iterator(temp);
    }

    /* For the "end" marker
     * we will use an iterator initialized to nil */
    const const_iterator end() const {
        return const_iterator(nullptr);
    }

这是我用 C++ 编写的有序迭代器的示例...

此迭代器假定 BST 中的每个节点都有一个指向父节点的指针,这是我在节点类中看不到的。但是,我不确定是否有可能在没有父指针的情况下完成中序遍历。

简而言之,如果您将父指针添加到节点并在每次执行节点插入或删除时更新父指针,则此示例将起作用

【讨论】:

  • +1。我认为您也应该显示begin() 函数,因为它执行迭代器初始化的重要部分。对于没有父节点的情况:您可以在迭代器内维护从根到当前节点的整个路径(例如,作为std::vector&lt;Node*&gt;)。
  • @jogojapan 感谢您提醒我,我完全忘记了 begin() 和 end() !我已经更新了我的答案以包括他们
  • 感谢您的帮助,乔希!我使用了某些部分,例如 begin() 和 end() 以及您的构造函数和运算符 != 和 =,并且我成功地测试了我的中序遍历。我选择保留我的 operator++,因为这是对具有关于此方法/函数的非常明确规范的类的分配,并且我在设计我的版本时考虑到了这些。还要感谢 @jogojapan 的 begin() 和 end() 建议,因为这些建议确实帮助我完成了迭代器的循环。
猜你喜欢
  • 2017-02-22
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 2011-10-18
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
相关资源
最近更新 更多