-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIterableMultiKeyRBT.java
More file actions
226 lines (185 loc) · 7.01 KB
/
Copy pathIterableMultiKeyRBT.java
File metadata and controls
226 lines (185 loc) · 7.01 KB
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
// --== CS400 Fall 2023 File Header Information ==--
// Name: Arnav Srivastav
// Email: asrivastav3@wisc.edu
// Group: C35
// TA: Alexander Peseckis
// Lecturer: Florian Heimerl
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Iterator;
import java.util.Stack;
import java.util.*;
public class IterableMultiKeyRBT<T extends Comparable<T>> extends RedBlackTree<KeyListInterface<T>> implements IterableMultiKeySortedCollectionInterface<T>{
private Comparable<T> iterationStartPoint;
private int numKeys = 0;
/**
* Inserts a single key into the tree.
*
* @param key the key to insert
* @return true if a new node was inserted, false if the key was added to an existing node
*/
@Override
public boolean insertSingleKey(T key) {
KeyListInterface<T> keyList = new KeyList<>(key);
Node<KeyListInterface<T>> existingNode = findNode(keyList);
if (existingNode != null) {
existingNode.data.addKey(key);
this.numKeys++;
return false;
} else {
super.insert(keyList);
this.numKeys++;
return true;
}
}
/**
* Returns the number of keys in the tree.
*
* @return the number of values in the tree
*/
@Override
public int numKeys() {
return this.numKeys; }
protected Stack<Node<KeyListInterface<T>>> getStartStack() {
Stack<Node<KeyListInterface<T>>> stack = new Stack<>();
Node<KeyListInterface<T>> currentNode = root;
while (currentNode != null) {
if (iterationStartPoint == null) {
stack.push(currentNode);
currentNode = currentNode.down[0];
} else {
int comparisonResult = iterationStartPoint.compareTo(currentNode.data.iterator().next());
if (comparisonResult < 0) {
stack.push(currentNode);
currentNode = currentNode.down[0];
} else if (comparisonResult > 0) {
currentNode = currentNode.down[1];
} else {
stack.push(currentNode);
break;
}
}
}
return stack;
}
/**
* Returns an iterator that does an in-order iteration over the tree.
*
* @return an iterator for in-order iteration
*/
public Iterator<T> iterator() {
Stack<Node<KeyListInterface<T>>> stack = getStartStack();
return new Iterator<T>() {
Iterator<T> currentKeyListIterator = (stack.isEmpty()) ? null : stack.peek().data.iterator();
@Override
public boolean hasNext() {
// If the currentKeyListIterator is not null and has more elements, return true.
if (currentKeyListIterator != null && currentKeyListIterator.hasNext()) {
return true;
}
// Otherwise, search for the next non-empty key list and update currentKeyListIterator.
while (!stack.isEmpty()) {
Node<KeyListInterface<T>> node = stack.pop();
if (node.down[1] != null) {
stack.push(node.down[1]);
node = node.down[1];
while (node.down[0] != null) {
stack.push(node.down[0]);
node = node.down[0];
}
}
if (!stack.isEmpty()) {
currentKeyListIterator = stack.peek().data.iterator();
if (currentKeyListIterator.hasNext()) {
return true;
}
}
}
// No more elements found, return false.
return false;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return currentKeyListIterator.next();
}
};
}
/**
* Sets the starting point for iterations. Future iterations will start at the
* starting point or the key closest to it in the tree. This setting is
* remembered until it is reset. Passing in null disables the starting point.
*
* @param startPoint the start point to set for iterations
*/
@Override
public void setIterationStartPoint(Comparable<T> startPoint) {
this.iterationStartPoint = startPoint;
}
public void clear() {
super.clear();
this.numKeys = 0; // Reset the number of keys to zero
}
/**
* Test basic iteration for the IterableMultiKeyRBT.
*/
@Test
public void testIterableMultiKeyRBTBasicIteration(){
IterableMultiKeyRBT<String> tree = new IterableMultiKeyRBT<>();
tree.insertSingleKey("M");
tree.insertSingleKey("U");
Iterator<String> iterator = tree.iterator();
Assertions.assertEquals("M",iterator.next());
Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals("U",iterator.next());
Assertions.assertFalse(iterator.hasNext());
}
@Test
public void testIterableMultiKeyRBTBasicIteration2() {
IterableMultiKeyRBT<Integer> tree = new IterableMultiKeyRBT<>();
tree.insertSingleKey(5);
tree.insertSingleKey(10);
Iterator<Integer> iterator = tree.iterator();
Assertions.assertEquals(5, iterator.next());
Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals(10, iterator.next());
Assertions.assertFalse(iterator.hasNext());
}
/**
* Checks if an iterator with a start point iterates over all keys
* equal to and larger than the start point.
*/
@Test
public void testIteratorStartPoint() {
IterableMultiKeyRBT<Integer> tree = new IterableMultiKeyRBT<>();
tree.insertSingleKey(5);
tree.insertSingleKey(25);
tree.insertSingleKey(30);
tree.setIterationStartPoint(20);
Assertions.assertEquals(25, tree.iterator().next());
tree.setIterationStartPoint(26);
Assertions.assertEquals(30, tree.iterator().next());
tree.setIterationStartPoint(null);
Assertions.assertEquals(5, tree.iterator().next());
}
@Test
public void submissionCheckerDuplicateKeys() {
IterableMultiKeyRBT<Integer> tree = new IterableMultiKeyRBT<>();
tree.insertSingleKey(50);
tree.insertSingleKey(50);
tree.insertSingleKey(100);
tree.insertSingleKey(100);
tree.insertSingleKey(150);
tree.insertSingleKey(150);
Assertions.assertEquals(3, tree.size());
Assertions.assertEquals(6, tree.numKeys());
int count = 0;
Iterator<Integer> iter = tree.iterator();
for (Integer key : tree) {
int expected = ((count++/2)+1)*50;
Assertions.assertEquals(expected, iter.next());
}
}
}