0

I'm new to c++ and I face some problems implementing the iterator on the template class Tree (structure of the code includes the canonical classes (Node,Tree,Iterator).

Fwd iterator is not working properly when tested (with the following extract) in the main:

  //expected result: 16 | 20 | 61 | 65 | 71 | 76 | 81 | 85 | 90 | 93 | 101 |
  
  auto it{rbt.begin()};
  auto end{rbt.end()};
  std::cout << *it << std::endl; // works fine=16
  std::cout << *end // works fine = set to nullptr, returns 0

  while(it!=end) {
    std::cout << *it << std::endl; 
    it++;
  } 

//getting alternatively the following errors when trying different solutions:
//A- just |16| and then iterator stops
//B- overflowing with |16|16|16|16|16|16|16|16|16|16|16 never stopping
//C- overflowing with |16|0|16|0|16|0|16|0|16|0|16|0|16 never stopping
//D- segmentation fault core (dump)

I suppose this is due to the way the Tree is created, in particular the fact of leaving some helper "NIL"s (pointers to initialized but empty nodes) alive in memory. They are necessary for other Tree methods (like insert/delete), but for what is my understanding are then interfering with the correct functioning of the iterator which, instead of simply skipping them, gets stuck somewhere. I have tried to do that myself changing the main condition of the operator++(): from

if(current_node->right!=nullptr)

to

if(current_node->right!=NIL)

within the iterator class, but I get the "invalid use of non-static data member ‘RBTree::NIL’" error, and I do not know what to do to fix it, letting the NIL private member of Tree be visible inside Iterator as well. Here the more details on the classes and a link with the complete code:

template <class T, class CMP>> 
class Tree {

public:
  typedef T node_type;
  typedef _Node<node_type> Node; ///< type of template tree node.
  typedef Node *NodePtr; ///< type of pointer to template tree node.

  class const_iterator;

private:
  NodePtr root;
  NodePtr NIL; ///< empty node, probable cause of the problem

Extract from the Iterator class:

    template <class T, class CMP> 
    class RBTree<T, CMP>::const_iterator {
      friend class RBTree;
    
    private:
      NodePtr current_node;
    
    public:
      const_iterator& operator++() { // this is the method causing issues
        if(current_node->right!=nullptr) {
          current_node = current_node->right->leftmost();
        }
        else {
          current_node = current_node->rightmost();
        }
        return *this;
}

and finally the Node class:

template <class T> 
class _Node {
public:
  friend class const_iterator; //allows const_iterator using leftmost() and rightmost()

  T data;                      //key
  Color color;                 //color
  _Node *left, *right, *parent; ///< pointers to parent, left and right children.

  //Default Constructor of a RBTree's node.
  _Node() {}

  _Node(T key, Color clr=BLACK, _Node *parent=nullptr) : data{key}, color{clr}, left{nullptr}, right{nullptr}, parent{parent} {}

  ~_Node() noexcept {}


  _Node* leftmost() noexcept {
    if(left!=nullptr) {
      return left->leftmost();
    }
    return this;
  }


  _Node* rightmost() const {
    if(parent!=nullptr) {
      if(parent->right==this) {
        return parent->rightmost();
      }
    }
      return parent;
  }

Thank you in advance if you would like to help me understand and improve my code: I know there may be many other errors around so please, any advice is very welcome and a way for me to grow my skills.

mpv
  • 1
  • 1
    Why is there one unique `NIL` value for each tree? – molbdnilo Sep 15 '22 at 07:40
  • From [wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Terminology): "The leaf nodes of red–black trees (NIL[...]) do not contain keys or data. These "leaves" need not be **explicit individuals** in computer memory: a NULL pointer can - as in all binary tree data structures - encode the fact that there is no child node at this position in the (parent) node." You must decide for yourself to either use `nullptr` to mark the abscence of a child or create a **new** NIL object for each leaf. Don't use a NIL singleton per tree. – Jakob Stark Sep 15 '22 at 08:01
  • Also you should never dereference a `nullptr`. This line: `std::cout << *end // works fine = set to nullptr, returns 0` should trigger a segmentation fault if `end` is indeed a `nullptr` – Jakob Stark Sep 15 '22 at 08:03
  • so, if I understand well your suggestion, your advice is to eliminate the NIL (empty) variable and substitute it with a nullptr from the beginning? The fact is that using NIL I was able to print out not only the "full" nodes but also the leaves, for example: (----- 0 BLACK (----- 81 BLACK R (----- 0 BLACK – mpv Sep 15 '22 at 08:27
  • cannot edit properly but here you have a terminal node with 81 and its left/right children with 0, with nullptr the terminal nodes would stop to 81. Your second comment about printing a nullptr is correct, in fact the `const_iterator RBTree::end() const { return const_iterator(nullptr);}` was initiially set to NIL – mpv Sep 15 '22 at 08:34
  • Cannot understand well the fact of the single NIL, and I think it is here the main issue: indeed a new NIL is already created each time I add a new node, in this way I keep adding -together with the full node- even a corresponding empty which will become a leave, in fact #leaves are always n+1, with n=#internal nodes, so this property is automatically enforced by the insert method: `insert(const T& value) { NodePtr node{new Node(value, RED)}; node->left = node->right = NIL;` etc.. – mpv Sep 15 '22 at 08:44
  • so my first thought was to simply continue using NIL as it is, but using it also within the iterator class..problem is with my current (poor) skills A am not able to let the iterator class "see" the NIL: I know it is a private variable of RBTree class, but as the const_iterator class is nested into RBTree and belongs to it, I thought that the iterator should have had access to it.. – mpv Sep 15 '22 at 08:52
  • 1
    identifiers starting with an underscore followed by a capital letter are reserved. Technically your code has undefined behavior – 463035818_is_not_an_ai Sep 15 '22 at 08:52

0 Answers0