aboutsummaryrefslogblamecommitdiffstats
path: root/src/algorithms/searching/MultibinarySearch.java
blob: 841a4ebff537e3c3a354c0c0355f1c320e1713bc (plain) (tree)








































































































































































                                                                                                                              
/**
 * Copyright © 2014  Mattias Andrée (maandree@member.fsf.org)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package algorithms.searching;

import java.util.*;


/**
 * Multibinary search class. Multibinary search runs with time complexity
 * 𝓞(log n + m) and memory complexity 𝓞(log m), where n is the number of
 * elements in the array to be searched, and m is the number of items for
 * which to search. Multibinary search locates multiple items in an array
 * effectively, the items to locate must however be unique and stored in
 * a sorted list. The algorithm only works with sorted arrays. Identity
 * search is not possible, only equality search. Null elements are not
 * allowed, unless the specified compator allows it.
 * 
 * This algorithm was devised by Mattias Andrée in February of 2013.
 */
public class MultibinarySearch
{
    /**
     * List sort order
     */
    public static enum SortOrder
    {
        /**
         * Bigger index, bigger value
         */
        ASCENDING,
        
        /**
         * Bigger index, smaller value
         */
        DESCENDING,
        
    }
    
    /**
     * List sort order
     */
    public static enum SearchMode
    {
        /**
         * Look for the index of the easiest to find occurence
         */
        FIND_ANY,
        
        /**
         * Look for the index of the first occurence
         */
        FIND_FIRST,
        
        /**
         * Look for the index of the last occurence
         */
        FIND_LAST,
        
        /**
         * Look for both the index of the fist occurence and of the last occurence.<br>
         * The returned value will be {@code (LAST << 32) | FIRST}.
         */
        FIND_FIST_AND_LAST,
        
    }
    
    
    
£>for T in boolean char byte short int long float double T T++; do . src/comparable
    /**
     * Find the indices of multiple items in a list, with time
     * complexity 𝓞(log n + m) and memory complexity 𝓞(log m)
     * 
     * @param   items  Sorted list of unique items for which to search, the number
     *                 of elements is named ‘m’ in the complexity analysis
     * @param   array  Sorted list in which to search, the number of elements
     *                 is named ‘n’ in the complexity analysis
     * @param   order  The lists' element order
     * @param   mode   The search mode
     * @return         Two arrays of integer arrays, the 0:th being the indices
     *                 of items, the 1:th being their positions. That is,
     *                 two separate arrays, not and array of pairs. The expected
     *                 position is returned inverted if it was not found, the
     *                 position it whould have upon be inserted, otherwise the
     *                 position is returned as an index if the mode does not
     *                 specify anything else.
     */
    public static £(fun "long[][]" indexOf "${T}[] items, ${Tarray} array, SortOrder order, SearchMode mode")
    {
	if (mode != SearchMode.FIND_ANY)
	    throw new Error("Mode not implemented"); /* TODO */
	if (order != SortOrder.ASCENDING)
	    throw new Error("Order not implemented"); /* TODO */
	
	BinarySearch.SearchMode mode_ = BinarySearch.SearchMode.FIND_ANY;
	BinarySearch.SortOrder order_ = BinarySearch.SortOrder.ASCENDING;
	
	int m = items.length, lb_m = 1;
	long[][] rc = new long[2][m];
	
	if (m == 0)
	    return rc;
	
	if ((m & 0xFFFF0000) != 0)  { lb_m |= 16;  m >>= 16; }
	if ((m & 0x0000FF00) != 0)  { lb_m |=  8;  m >>=  8; }
	if ((m & 0x000000F0) != 0)  { lb_m |=  4;  m >>=  4; }
	if ((m & 0x0000000C) != 0)  { lb_m |=  2;  m >>=  2; }
	if ((m & 0x00000002) != 0)  { lb_m +=  1; }
	
        int[][] minomax = new int[4][lb_m];
	int n = array.length - 1;
	m = items.length - 1;
	
	int rc_i = 0;
	int mm_i = 0;
	int min, max, amin = 0, amax = 0, lastmax, lastamax;
	
	minomax[0][mm_i] = 0;
	minomax[1][mm_i] = m;
	minomax[2][mm_i] = 0;
	minomax[3][mm_i++] = n;
	
	while (mm_i-- > 0)
	{
	    min = minomax[0][mm_i];
	    max = minomax[1][mm_i];
	    amin = minomax[2][mm_i];
	    amax = minomax[3][mm_i];
	    
	    while (max != min)
	    {
		lastmax = max;
		lastamax = amax;
		rc[0][rc_i] = max = min + ((max - min) >>> 1);
		rc[1][rc_i++] = amax = (int)(BinarySearch.indexOf(items[max], array, order_, mode_, amin, amax£{Targ_name}));
		if (amax < 0)
		    amax = ~amax;
		
		minomax[0][mm_i] = max + 1;
		minomax[1][mm_i] = lastmax;
		minomax[2][mm_i] = amax + 1;
		minomax[3][mm_i++] = lastamax;
	    }
	}
	
	max = m;
	amax = (int)(BinarySearch.indexOf(items[max], array, order_, mode_, amin, amax£{Targ_name}));
	rc[0][rc_i] = max;
	rc[1][rc_i++] = amax;
	
	return rc;
    }
£>done
}