Need Help with a Couple of Set Class Functions

Hi there!

I've been working on a set class implementation but have gotten confused on certain parts of the code, specifically the functions erase, find and begin in the Set class. I'm pretty sure I am doing my begin function incorrectly, but I am stumped as to what it could be... I completely understand the inline erase function I have, but am confused with the second. Also completely confused on how the find function works in sets...

Note: This program runs in inorder traversal, so it will read from left node to root, to right node.

Here's the functions alone I am confused with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template <class T>
void Set<T>::erase(const iterator & current)
{
    
}

template <class T>
typename Set<T>::iterator Set<T>::find(const T & element) const
{

}

template <class T>
typename Set<T>::iterator Set<T>::begin() const
{
    return iterator(root); //pretty sure this is incorrect, since this program reads in inorder traversal. 
//Shouldn't the first element of the set be a left node?
}


Here's the full .h file that I am working on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#ifndef SET_H
#define SET_H

// Set.h - an implementation of Set using Node and Set_iterator

using namespace std;

template <class T> class Set;
template <class T> class Set_iterator;

template <class T>
class Node {
public:
	Node(): value(0), parent(0), leftChild(0), rightChild(0) { }
   Node(const T & x, Node * p, Node * lc, Node * rc): value(x), parent(p), leftChild(lc), rightChild(rc) { }
    // here copy constructor and assignment op don't make too much sense!
        Node(const Node & n): value(n.value), parent(0), leftChild(0), rightChild(0) { }
        Node & operator=(const Node & n) { value = n.value; return *this; }
    
	~Node() { delete leftChild; delete rightChild; } // this is very recursive, 
//delete also calls the destructor of the object it is deleting
    
	void insert(Node<T> * newNode); // this is a helper func for Set::insert()
	Node * find(const T & x);
	Node * merge(Node<T> * left, Node<T> * right);
protected:
	T value;
	Node * parent;
	Node * leftChild;
	Node * rightChild;
    
    friend class Set<T>;
    friend class Set_iterator<T>;
};

template <class T>
void Node<T>::insert(Node<T> * newNode)
{
    if(newNode->value <= value){
        if(leftChild != 0){
            leftChild->insert (newNode);
        }
        else{
            newNode->parent = this;
            leftChild = newNode;
        }
    }
    else{
        if(rightChild != 0){
            rightChild->insert (newNode);
        }
        else{
            newNode->parent = this;
            rightChild = newNode;
        }
    }
    
}
 
template <class T>
Node<T> * Node<T>::find(const T & element)
{
    if(element->value <= value){
        if(leftChild != 0){
            if(leftChild->value == element){;
                return *this;
            }
            else{
                return element;
            }
        }
        else{
            return element;
        }
    }
    else{
        if(rightChild != 0){
            if(rightChild->value == element){
                return *this;
            }
            else{
                return element;
            }
        }
        else{
            return element;
        }
    }
    return setIterator(this);
}

template <class T>
Node<T> * Node<T>::merge(Node<T> *left, Node<T> *right)
{
    if(left == 0){
        return right;
    }
    if(right == 0){
        return left;
    }
    Node<T> * child = merge(left, right->leftChild);
    child->parent = right;
    right->leftChild = child;
    return right;
}

template <class T>
class Set {
public:
	typedef Set_iterator<T> iterator;
    
	Set(): root(0), my_size(0) { }
    
	// the big three
	Set(const Set<T> & );
	~Set() { delete root; }
	Set operator=(const Set & );
    
	bool empty() const { return root == 0; }
	unsigned int size() const { return my_size; }
	void insert(const T & newElement); // return an iterator to x if it already exists,
// otherwise insert and return an iterator to x
	void erase(const iterator & current);
	void erase(const T & x) { root = remove(root, x); }
	unsigned int count(const T & x) const; // returns 1 or 0 because this is a set, not a multi-set
	iterator find(const T & x) const;
	iterator begin() const; // for in-order traversal
	iterator end() const { return iterator(0); }
protected:
	Node<T> * root;
	unsigned int my_size;
	Node<T> * remove(Node<T> *, const T &);
};

template <class T>
Set<T>::Set(const Set<T> & op)
{
    root = 0;
    for (iterator i = op.begin(); i != op.end(); ++i)
        insert(*i);
}

template <class T>
Set<T> Set<T>::operator=(const Set<T> & op)
{
    delete root;
    root = 0;
    for (iterator i = op.begin(); i != op.end(); ++i)
        insert(*i);
    return *this;
}

template <class T>
void Set<T>::insert(const T & newElement)
{
    //do not insert if already in set
    if (count(newElement) > 0){
        return;
    }
    //create a new node
    Node<T> * newNode = new Node<T> (newElement, 0, 0, 0);
    if(root == 0){
        root = newNode;
    }
    else{
        root->insert (newNode);
    }
}

template <class T>
void Set<T>::erase(const iterator & current)
{
    
}

template <class T>
unsigned int Set<T>::count(const T & x) const
{
    iterator looking = begin();
    int count = 0;
    
    for( ; looking != end(); looking++){
        count++;
    }
    return count;
}

template <class T>
typename Set<T>::iterator Set<T>::find(const T & element) const
{

}

template <class T>
typename Set<T>::iterator Set<T>::begin() const
{
    return iterator(root);
}

template <class T>
Node<T> * Set<T>::remove(Node<T> * current, const T & testElement)
{
    if(current != 0){
        Node<T> * pa = current->parent;
        if(testElement < current->value){
            current->leftChild = remove(current->leftChild, testElement);
        }
        else if(current->value < testElement){
            current->rightChild = remove(current->rightChild, testElement);
        }
        else {
            Node<T> * result = current->merge(remove(current->leftChild, testElement), current->rightChild);
            current->leftChild = current->rightChild = 0;
            delete current;
            if (result)
                result->parent = pa;
            return result;
        }
    }
}
    
template <class T>
class Set_iterator {
public:
	Set_iterator(): current(0) { }
	Set_iterator(Node<T> * newNode): current(newNode) { }
    
	bool operator==(Set_iterator it) const { return current == it.current; }
	bool operator!=(Set_iterator it) const { return current != it.current; }
	Set_iterator & operator++(); // inorder traversal, pre-increment
	Set_iterator operator++(int); // inorder traversal, post-increment
	T & operator*() { return current->value; }
	Set_iterator & operator=(Set_iterator<T> it) { current = it.current; return *this; }
protected:
	Node<T> * current;
    friend class Set<T>;
};

template <class T>
Set_iterator<T> & Set_iterator<T>::operator++()
{
    if(current->rightChild){
        current = current->rightChild;
        while(current->leftChild){
            current = current->leftChild;
        }
    }
    else{
        Node<T> * child = current;
        current = current->parent;
        while(current && current->rightChild == current){
            child = current;
            current = current->parent;
        }
    }
    return *this;
}

template <class T>
Set_iterator<T> Set_iterator<T>::operator++(int)
{
    Set_iterator<T> clone (*this);
    operator++ ();
    return clone;
}


#endif 


Here's the main file I am first testing with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cassert>
#include "set.h"

using namespace std;

main()
{
    Set<int> s;
    
    s.insert(10);
    s.insert(7);
    s.insert(6);
    s.insert(9);
    s.insert(8);
    s.insert(11);
    
    Set<int>::iterator i = s.find(7);
    s.erase(i);
    
    for (i = s.begin(); i != s.end(); i++)
        cout << *i << endl;
    
    cout << "All tests passed." << endl;
}
Last edited on
The begin function should return the left-most leaf in the tree.

I think line 151 should be while(current && current->rightChild == child){.

The find should search for the element passed in to it, and if it is found an iterator to the element that was found in the set is returned. If it is not found end() is returned. At least that's how std::set::find works.
Hmm, I tried modifying the while loop as you suggested but now get a segmentation fault.

Also how would I return the left-most left in the tree without access to the leftChild variable that's in class Node? Likewise, how do I set up the find function without the access to the Left and Right child variables?
Last edited on
You do have access to leftChild because Set<T> is a friend of Node<T>.
How come I keep getting 'undeclared variable' errors though, when trying to use say "leftChild" in a Set function?
You need to use a Node<T> object to access leftChild. You can use root. Or if you don't want to access leftChild from Set<T> you can create a member function of Node<T> that returns the left most leaf.
Alright, thank you Peter, I believe I got the find and begin functions now! :D

Anyone know how I would approach the erase function?
Topic archived. No new replies allowed.