Int Set
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
*
* This program and the accompanying materials are made available under
* the terms of the Common Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/cpl-v10.html
*
* $Id: IntSet.java,v 1.1.1.1 2004/05/09 16:57:53 vlad_r Exp $
*/
// ----------------------------------------------------------------------------
/**
*
* MT-safety: an instance of this class is <I>not</I> safe for access from
* multiple concurrent threads [even if access is done by a single thread at a
* time]. The caller is expected to synchronize externally on an instance [the
* implementation does not do internal synchronization for the sake of efficiency].
* java.util.ConcurrentModificationException is not supported either.
*
* @author Vlad Roubtsov, (C) 2001
*/
public
final class IntSet
{
// public: ................................................................
/**
* Equivalent to <CODE>IntSet(11, 0.75F)</CODE>.
*/
public IntSet ()
{
this (11, 0.75F);
}
/**
* Equivalent to <CODE>IntSet(capacity, 0.75F)</CODE>.
*/
public IntSet (final int initialCapacity)
{
this (initialCapacity, 0.75F);
}
/**
* Constructs an IntSet with specified initial capacity and load factor.
*
* @param initialCapacity initial number of hash buckets in the table [may not be negative, 0 is equivalent to 1].
* @param loadFactor the load factor to use to determine rehashing points [must be in (0.0, 1.0] range].
*/
public IntSet (int initialCapacity, final float loadFactor)
{
if (initialCapacity < 0) throw new IllegalArgumentException ("negative input: initialCapacity [" + initialCapacity + "]");
if ((loadFactor <= 0.0) || (loadFactor >= 1.0 + 1.0E-6))
throw new IllegalArgumentException ("loadFactor not in (0.0, 1.0] range: " + loadFactor);
if (initialCapacity == 0) initialCapacity = 1;
m_loadFactor = loadFactor > 1.0 ? 1.0F : loadFactor;
m_sizeThreshold = (int) (initialCapacity * loadFactor);
m_buckets = new Entry [initialCapacity];
}
/**
* Overrides Object.toString() for debug purposes.
*/
public String toString ()
{
final StringBuffer s = new StringBuffer ();
debugDump (s);
return s.toString ();
}
/**
* Returns the number of key-value mappings in this map.
*/
public int size ()
{
return m_size;
}
public boolean contains (final int key)
{
// index into the corresponding hash bucket:
final Entry [] buckets = m_buckets;
final int bucketIndex = (key & 0x7FFFFFFF) % buckets.length;
// traverse the singly-linked list of entries in the bucket:
for (Entry entry = buckets [bucketIndex]; entry != null; entry = entry.m_next)
{
if (key == entry.m_key)
return true;
}
return false;
}
public int [] values ()
{
if (m_size == 0)
return new int[0];
else
{
final int [] result = new int [m_size];
int scan = 0;
for (int b = 0; b < m_buckets.length; ++ b)
{
for (Entry entry = m_buckets [b]; entry != null; entry = entry.m_next)
{
result [scan ++] = entry.m_key;
}
}
return result;
}
}
public void values (final int [] target, final int offset)
{
if (m_size != 0)
{
int scan = offset;
for (int b = 0; b < m_buckets.length; ++ b)
{
for (Entry entry = m_buckets [b]; entry != null; entry = entry.m_next)
{
target [scan ++] = entry.m_key;
}
}
}
}
public boolean add (final int key)
{
Entry currentKeyEntry = null;
// detect if 'key' is already in the table [in which case, set 'currentKeyEntry' to point to its entry]:
// index into the corresponding hash bucket:
int bucketIndex = (key & 0x7FFFFFFF) % m_buckets.length;
// traverse the singly-linked list of entries in the bucket:
Entry [] buckets = m_buckets;
for (Entry entry = buckets [bucketIndex]; entry != null; entry = entry.m_next)
{
if (key == entry.m_key)
{
currentKeyEntry = entry;
break;
}
}
if (currentKeyEntry == null)
{
// add a new entry:
if (m_size >= m_sizeThreshold) rehash ();
buckets = m_buckets;
bucketIndex = (key & 0x7FFFFFFF) % buckets.length;
final Entry bucketListHead = buckets [bucketIndex];
final Entry newEntry = new Entry (key, bucketListHead);
buckets [bucketIndex] = newEntry;
++ m_size;
return true;
}
else
return false;
}
// protected: .............................................................
// package: ...............................................................
void debugDump (final StringBuffer out)
{
if (out != null)
{
out.append (super.toString ()); out.append (EOL);
out.append ("size = " + m_size + ", bucket table size = " + m_buckets.length + ", load factor = " + m_loadFactor + EOL);
out.append ("size threshold = " + m_sizeThreshold + EOL);
}
}
// private: ...............................................................
/**
* The structure used for chaining colliding keys.
*/
private static final class Entry
{
Entry (final int key, final Entry next)
{
m_key = key;
m_next = next;
}
final int m_key;
Entry m_next; // singly-linked list link
} // end of nested class
/**
* Re-hashes the table into a new array of buckets.
*/
private void rehash ()
{
// TODO: it is possible to run this method twice, first time using the 2*k+1 prime sequencer for newBucketCount
// and then with that value reduced to actually shrink capacity. As it is right now, the bucket table can
// only grow in size
final Entry [] buckets = m_buckets;
final int newBucketCount = (m_buckets.length << 1) + 1;
final Entry [] newBuckets = new Entry [newBucketCount];
// rehash all entry chains in every bucket:
for (int b = 0; b < buckets.length; ++ b)
{
for (Entry entry = buckets [b]; entry != null; )
{
final Entry next = entry.m_next; // remember next pointer because we are going to reuse this entry
final int entryKey = entry.m_key;
// index into the corresponding new hash bucket:
final int newBucketIndex = (entryKey & 0x7FFFFFFF) % newBucketCount;
final Entry bucketListHead = newBuckets [newBucketIndex];
entry.m_next = bucketListHead;
newBuckets [newBucketIndex] = entry;
entry = next;
}
}
m_sizeThreshold = (int) (newBucketCount * m_loadFactor);
m_buckets = newBuckets;
}
private final float m_loadFactor; // determines the setting of m_sizeThreshold
private Entry [] m_buckets; // table of buckets
private int m_size; // number of keys in the table, not cleared as of last check
private int m_sizeThreshold; // size threshold for rehashing
private static final String EOL = System.getProperty ("line.separator", "\n");
} // end of class
// ----------------------------------------------------------------------------
Related examples in the same category
1. | Set, HashSet and TreeSet | | |
2. | Things you can do with Sets | | |
3. | Set operations: union, intersection, difference, symmetric difference, is subset, is superset | | |
4. | Set implementation that use == instead of equals() | | |
5. | Set that compares object by identity rather than equality | | |
6. | Set union and intersection | | |
7. | Set with values iterated in insertion order. | | |
8. | Putting your own type in a Set | | |
9. | Use set | | |
10. | Another Set demo | | |
11. | Set subtraction | | |
12. | Working with HashSet and TreeSet | | |
13. | TreeSet Demo | | |
14. | Show the union and intersection of two sets | | |
15. | Demonstrate the Set interface | | |
16. | Array Set extends AbstractSet | | |
17. | Sync Test | | |
18. | Set Copy | | |
19. | Set and TreeSet | | |
20. | Tail | | |
21. | What you can do with a TreeSet | | |
22. | Remove all elements from a set | | |
23. | Copy all the elements from set2 to set1 (set1 += set2), set1 becomes the union of set1 and set2 | | |
24. | Remove all the elements in set1 from set2 (set1 -= set2), set1 becomes the asymmetric difference of set1 and set2 | | |
25. | Get the intersection of set1 and set2, set1 becomes the intersection of set1 and set2 | | |
26. | Extend AbstractSet to Create Simple Set | | |
27. | One Item Set | | |
28. | Small sets whose elements are known to be unique by construction | | |
29. | List Set implements Set | | |
30. | Converts a char array to a Set | | |
31. | Converts a string to a Set | | |
32. | Implements the Set interface, backed by a ConcurrentHashMap instance | | |
33. | An IdentitySet that uses reference-equality instead of object-equality | | |
34. | An implementation of the java.util.Stack based on an ArrayList instead of a Vector, so it is not synchronized to protect against multi-threaded access. | | |
35. | A thin wrapper around a List transforming it into a modifiable Set. | | |
36. | A thread-safe Set that manages canonical objects | | |
37. | This program uses a set to print all unique words in System.in | | |
38. | Indexed Set | | |
39. | An ObjectToSet provides a java.util.Map from arbitrary objects to objects of class java.util.Set. | | |
40. | Sorted Multi Set | | |
41. | Fixed Size Sorted Set | | |
42. | Set operations | | |
43. | A NumberedSet is a generic container of Objects where each element is identified by an integer id. | | |
44. | Set which counts the number of times a values are added to it. | | |
45. | Set which counts the number of times a values are added to it and assigns them a unique positive index. | | |
46. | Indexed Set | | |
47. | A set acts like array. | | |
48. | Implements a Bloom filter. Which, as you may not know, is a space-efficient structure for storing a set. | | |
49. | Implementation of disjoint-set data structure | | |
50. | Call it an unordered list or a multiset, this collection is defined by oxymorons | | |