Skip to content
This repository was archived by the owner on Jul 7, 2020. It is now read-only.

Commit 4daaa62

Browse files
committed
Merge pull request #11 from jkff/sample-set
More "obviously correct" code in SampleSet.
2 parents e525d4a + a856df7 commit 4daaa62

File tree

1 file changed

+81
-104
lines changed

1 file changed

+81
-104
lines changed

src/main/java/com/clearspring/analytics/stream/SampleSet.java

+81-104
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
public class SampleSet<T> implements ISampleSet<T>
2626
{
27-
private Map<T,Node<T>> sampleMap;
27+
private Map<T, Node<T>> sampleMap;
2828
private int size;
2929
private long count;
3030
private Random random;
@@ -51,45 +51,45 @@ public SampleSet(int capacity)
5151

5252
public SampleSet(int capacity, Random random)
5353
{
54-
sampleMap = new HashMap<T,Node<T>>(capacity);
54+
sampleMap = new HashMap<T, Node<T>>(capacity);
5555
this.random = random;
5656
}
5757

5858
public T peek()
59-
{return (head != null) ? head.element : null;}
59+
{
60+
return (head != null) ? head.element : null;
61+
}
6062

6163
public List<T> peek(int k)
6264
{
6365
List<T> topK = new ArrayList<T>(k);
64-
Node<T> itr = head;
65-
int i=0;
66-
while(i++<k && itr != null)
66+
for (Node<T> itr = head; itr != null && topK.size() < k; itr = itr.next)
6767
{
6868
topK.add(itr.element);
69-
itr = itr.next;
70-
}
69+
}
7170
return topK;
7271
}
7372

7473
public long put(T element)
7574
{
7675
Node<T> node = sampleMap.get(element);
77-
if(node != null)
76+
if (node != null)
7877
{
7978
node.count++;
8079
promote(node);
8180
}
8281
else
8382
{
84-
node = new Node<T>(element);
83+
node = new Node<T>();
84+
node.element = element;
8585
node.count = 1;
8686
node.prev = tail;
87-
if(tail != null)
87+
if (tail != null)
8888
{
8989
tail.next = node;
9090
}
9191
tail = node;
92-
if(head == null)
92+
if (head == null)
9393
{
9494
head = node;
9595
}
@@ -103,123 +103,106 @@ public long put(T element)
103103
public T removeRandom()
104104
{
105105
double p = random.nextDouble();
106-
Node<T> itr = head;
107106
long weight = 0;
108-
while(itr != null)
107+
for (Node<T> itr = head; itr != null; itr = itr.next)
109108
{
110109
weight += itr.count;
111-
if(p < weight/(double)count)
112-
{
113-
break;
114-
}
115-
itr = itr.next;
116-
}
117-
118-
T removed = null;
119-
if(itr != null)
120-
{
121-
removed = itr.element;
122-
itr.count--;
123-
count--;
124-
demote(itr);
125-
if(itr.count == 0)
110+
if (p < weight / (double) count)
126111
{
127-
removeMin();
112+
itr.count--;
113+
count--;
114+
demote(itr);
115+
if (itr.count == 0)
116+
{
117+
removeMin();
118+
}
119+
return itr.element;
128120
}
129121
}
130-
131-
return removed;
122+
return null;
132123
}
133124

134125
protected T removeMin()
135126
{
136-
T minElement = null;
137-
if(tail != null)
127+
if (tail == null)
138128
{
139-
size--;
140-
count -= tail.count;
141-
minElement = tail.element;
142-
tail = tail.prev;
143-
if(tail != null)
144-
{
145-
tail.next = null;
146-
}
147-
sampleMap.remove(minElement);
129+
return null;
130+
}
131+
size--;
132+
count -= tail.count;
133+
T minElement = tail.element;
134+
tail = tail.prev;
135+
if (tail != null)
136+
{
137+
tail.next = null;
148138
}
139+
sampleMap.remove(minElement);
149140
return minElement;
150141
}
151142

152143
public int size()
153-
{return size;}
144+
{
145+
return size;
146+
}
154147

155148
public long count()
156-
{return count;}
149+
{
150+
return count;
151+
}
157152

158153
protected T peekMin()
159-
{return tail.element;}
154+
{
155+
return tail.element;
156+
}
160157

161-
protected int promote(Node<T> node)
158+
protected void promote(Node<T> node)
162159
{
163-
int promotion = 0;
164-
while(node.prev != null && node.count > node.prev.count)
160+
// Bring node closer to the head as necessary
161+
while (node.prev != null && node.count > node.prev.count)
165162
{
166-
node.prev.next = node.next;
167-
node.next = node.prev;
168-
node.prev = node.next.prev;
169-
node.next.prev = node;
170-
if(node.prev != null)
171-
{
172-
node.prev.next = node;
173-
}
174-
else
175-
{
176-
head = node;
177-
}
178-
if(node.next.next != null)
179-
{
180-
node.next.next.prev = node.next;
181-
}
182-
else
183-
{
184-
tail = node.next;
185-
}
163+
// BEFORE head... [A]node.prev.prev --> [B]node.prev --> [C]node --> [D]node.next ...tail
164+
// AFTER head... [A]node.prev.prev --> [C]node --> [B]node.prev --> [D]node.next ...tail
165+
Node<T> b = node.prev, c = node, d = node.next, a = (b == null) ? null : b.prev;
166+
167+
// Re-link each of 3 neighboring pairs
168+
if (a != null) a.next = c;
169+
c.prev = a;
170+
171+
c.next = b;
172+
b.prev = c;
186173

187-
promotion++;
174+
b.next = d;
175+
if (d != null) d.prev = b;
176+
177+
// B and C may have switched head/tail roles
178+
if (head == b) head = c;
179+
if (tail == c) tail = b;
188180
}
189-
return promotion;
190181
}
191182

192-
protected int demote(Node<T> node)
183+
protected void demote(Node<T> node)
193184
{
194-
int demotion = 0;
195-
196-
while(node.next != null && node.count < node.next.count)
185+
// Bring node closer to the tail as necessary
186+
while (node.next != null && node.count < node.next.count)
197187
{
198-
node.next.prev = node.prev;
199-
node.prev = node.next;
200-
node.next = node.prev.next;
201-
node.prev.next = node;
202-
if(node.next != null)
203-
{
204-
node.next.prev = node;
205-
}
206-
else
207-
{
208-
tail = node;
209-
}
210-
if(node.prev.prev != null)
211-
{
212-
node.prev.prev.next = node.prev;
213-
}
214-
else
215-
{
216-
head = node.prev;
217-
}
188+
// BEFORE head... [A]node.prev --> [B]node --> [C]node.next --> [D]node.next.next ...tail
189+
// AFTER head... [A]node.prev --> [C]node.next --> [B]node --> [D]node.next.next ...tail
190+
Node<T> a = node.prev, b = node, c = node.next, d = (c == null) ? null : c.next;
218191

219-
demotion++;
220-
}
192+
// Re-link each of 3 neighboring pairs
193+
if (a != null) a.next = c;
194+
c.prev = a;
195+
196+
c.next = b;
197+
b.prev = c;
221198

222-
return demotion;
199+
if (d != null) d.prev = b;
200+
b.next = d;
201+
202+
// B and C may have switched head/tail roles
203+
if (head == b) head = c;
204+
if (tail == c) tail = b;
205+
}
223206
}
224207

225208
private class Node<E>
@@ -228,11 +211,5 @@ private class Node<E>
228211
private Node<E> prev;
229212
private E element;
230213
private long count;
231-
232-
public Node(E element)
233-
{
234-
this.element = element;
235-
}
236214
}
237-
238215
}

0 commit comments

Comments
 (0)