blob: e08b999e22ffca8e740f7a7dc407afa3f4df152f [file] [log] [blame] [edit]
/*
* Copyright (c) 2014-2021 by Wen Yu
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* or any later version.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
*/
package pixy.util;// Temporarily put in this package
/**
* A hash table using primitive integer keys.
*
* @author Wen Yu, yuwen_66@yahoo.com
* @version 1.0 01/06/2008
*
* Based on
* QuadraticProbingHashTable.java
* <p>
* Probing table implementation of hash tables.
* Note that all "matching" is based on the equals method.
*
* @author Mark Allen Weiss
*/
public class IntHashtable<E>
{
private static final int DEFAULT_TABLE_SIZE = 257;
/** The array of HashEntry. */
private HashEntry<E> [ ] array; // The array of HashEntry
private int currentSize; // The number of occupied cells
/**
* Construct the hash table.
*/
public IntHashtable( )
{
this( DEFAULT_TABLE_SIZE );
}
/**
* Construct the hash table.
* @param size the approximate initial size.
*/
@SuppressWarnings("unchecked")
public IntHashtable( int size )
{
array = new HashEntry [size];
makeEmpty( );
}
/**
* Insert into the hash table. If the item is
* already present, do nothing.
* @param key the item to insert.
*/
public void put( int key, E value )
{
// Insert key as active
int currentPos = locate( key );
if( isActive( currentPos ) )
return;
array[ currentPos ] = new HashEntry<E> ( key, value, true );
// Rehash
if( ++currentSize > array.length / 2 )
rehash( );
}
/**
* Expand the hash table.
*/
@SuppressWarnings("unchecked")
private void rehash( )
{
HashEntry<E> [ ] oldArray = array;
// Create a new double-sized, empty table
array = new HashEntry [ nextPrime( 2 * oldArray.length ) ];
currentSize = 0;
// Copy table over
for( int i = 0; i < oldArray.length; i++ )
if( oldArray[i] != null && oldArray[i].isActive )
put( oldArray[i].key, oldArray[i].value );
return;
}
/**
* Method that performs quadratic probing resolution.
* @param key the item to search for.
* @return the index of the item.
*/
private int locate( int key )
{
int collisionNum = 0;
// And with the largest positive integer
int currentPos = (key & 0x7FFFFFFF) % array.length;
while( array[ currentPos ] != null &&
array[ currentPos ].key != key )
{
currentPos += 2 * ++collisionNum - 1; // Compute ith probe
if( currentPos >= array.length ) // Implement the mod
currentPos -= array.length;
}
return currentPos;
}
/**
* Remove from the hash table.
* @param key the item to remove.
*/
public void remove( int key )
{
int currentPos = locate( key );
if( isActive( currentPos ) )
{
array[ currentPos ].isActive = false;
currentSize--;
}
}
/**
* Search for an item in the hash table.
* @param key the item to search for.
* @return true if a matching item found.
*/
public boolean contains(int key)
{
return isActive( locate( key ) );
}
/**
* Find an item in the hash table.
* @param key the item to search for.
* @return the value of the matching item.
*/
public E get( int key )
{
int currentPos = locate( key );
return isActive( currentPos ) ? array[ currentPos ].value : null;
}
/**
* Return true if currentPos exists and is active.
* @param currentPos the result of a call to findPos.
* @return true if currentPos is active.
*/
private boolean isActive( int currentPos )
{
return array[ currentPos ] != null && array[ currentPos ].isActive;
}
/**
* Make the hash table logically empty.
*/
public void makeEmpty( )
{
currentSize = 0;
for( int i = 0; i < array.length; i++ )
array[ i ] = null;
}
/**
* Internal method to find a prime number at least as large as n.
* @param n the starting number (must be positive).
* @return a prime number larger than or equal to n.
*/
private static int nextPrime( int n )
{
if( n % 2 == 0 )
n++;
for( ; !isPrime( n ); n += 2 )
;
return n;
}
/**
* Internal method to test if a number is prime.
* Not an efficient algorithm.
* @param n the number to test.
* @return the result of the test.
*/
private static boolean isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
// The basic entry stored in ProbingHashTable
private static class HashEntry<V>
{
int key; // the key
V value; // the value
boolean isActive; // false if deleted
@SuppressWarnings("unused")
HashEntry( int k, V val )
{
this( k, val, true );
}
HashEntry( int k, V val, boolean i )
{
key = k;
value = val;
isActive = i;
}
}
// Simple main
public static void main( String [ ] args )
{
IntHashtable<Integer> H = new IntHashtable<Integer> ( );
final int NUMS = 4000;
final int GAP = 37;
System.out.println( "Checking... (no more output means success)" );
for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
H.put( i, new Integer(i) );
for( int i = 1; i < NUMS; i+= 2 )
H.remove( i );
for( int i = 2; i < NUMS; i+=2 )
if( H.get(i) != i )
System.out.println( "Find fails " + i );
for( int i = 1; i < NUMS; i+=2 )
{
if( H.get(i) != null )
System.out.println( "OOPS!!! " + i );
}
}
}