/**
* Copyright © 2014 Mattias Andrée (m@maandree.se)
*
* 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 .
*/
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.
* The returned value will be {@code (LAST << 32) | FIRST}.
*/
FIND_FIRST_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' (both) 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")
{
return indexOf(items, array, order, mode, 0, array.length - 1£{Targ_name});
}
/**
* 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' (both) element order
* @param mode The search mode
* @param start The index of the first position to search in the array
* @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, int start")
{
return indexOf(items, array, order, mode, start, array.length - 1£{Targ_name});
}
/**
* 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' (both) element order
* @param mode The search mode
* @param start The index of the first position to search in the array
* @param end The index after the last position to search in the array
* @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, int start, int end")
{
BinarySearch.SearchMode mode_ =
mode == SearchMode.FIND_ANY ? BinarySearch.SearchMode.FIND_ANY
: mode == SearchMode.FIND_FIRST ? BinarySearch.SearchMode.FIND_FIRST
: mode == SearchMode.FIND_LAST ? BinarySearch.SearchMode.FIND_LAST
: BinarySearch.SearchMode.FIND_FIRST_AND_LAST;
BinarySearch.SortOrder order_ = order == SortOrder.ASCENDING
? BinarySearch.SortOrder.ASCENDING
: BinarySearch.SortOrder.DESCENDING;
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];
m = items.length - 1;
int rc_i = 0;
int mm_i = 0;
int imin, imax, amin = 0, amax = 0, lastimax, lastamax;
minomax[0][mm_i] = 0;
minomax[1][mm_i] = m;
minomax[2][mm_i] = start;
minomax[3][mm_i++] = end - 1;
£>bin_search="BinarySearch.indexOf(items[imax], array, order_, mode_, amin, amax${Targ_name})"
while (mm_i-- > 0)
{
imin = minomax[0][mm_i];
imax = minomax[1][mm_i];
amin = minomax[2][mm_i];
amax = minomax[3][mm_i];
while (imax != imin)
{
lastimax = imax;
lastamax = amax;
rc[0][rc_i] = imax = imin + ((imax - imin) >>> 1);
amax = (int)(rc[1][rc_i++] = £{bin_search});
if (amax < 0)
amax = ~amax;
/* This is possible to do, but you will probably lose performance:
else if (mode == SearchMode.FIND_FIRST_AND_LAST)
amax = (int)(rc[1][rc_i - 1] >> 32L);
*/
minomax[0][mm_i] = imax + 1;
minomax[1][mm_i] = lastimax;
minomax[2][mm_i] = amax + 1;
minomax[3][mm_i++] = lastamax;
}
}
imax = m;
amax = (int)(£{bin_search});
rc[0][rc_i] = imax;
rc[1][rc_i++] = amax;
return rc;
}
£>done
}