| /* |
| * 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 ); |
| } |
| } |
| } |