performamce tuning
This commit is contained in:
parent
ead7f2ac6d
commit
51ff1b8482
1 changed files with 197 additions and 183 deletions
|
@ -2,24 +2,21 @@ package btools.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory efficient Heap to get the lowest-key value
|
* Memory efficient Heap to get the lowest-key value of a set of key-object pairs
|
||||||
* of a set of key-object pairs
|
|
||||||
*
|
*
|
||||||
* @author ab
|
* @author ab
|
||||||
*/
|
*/
|
||||||
public class SortedHeap<V>
|
public final class SortedHeap<V>
|
||||||
{
|
{
|
||||||
private int[][] al;
|
private int[][] al;
|
||||||
private int[] pa;
|
|
||||||
private int[] lp; // the low pointers
|
private int[] lp; // the low pointers
|
||||||
|
|
||||||
private Object[][] vla; // value list array
|
private Object[][] vla; // value list array
|
||||||
|
|
||||||
protected static final int MAXLISTS = 31; // enough for size Integer.MAX_VALUE
|
protected static final int MAXLISTS = 28; // enough for size = ca Integer.MAX_VALUE
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
private boolean isClear = false;
|
private boolean isClear = false;
|
||||||
|
@ -34,113 +31,96 @@ public class SortedHeap<V>
|
||||||
*/
|
*/
|
||||||
public V popLowestKeyValue()
|
public V popLowestKeyValue()
|
||||||
{
|
{
|
||||||
int minId = 0;
|
int minId = 0;
|
||||||
int minIdx = -1;
|
int minIdx = -1;
|
||||||
for ( int i=1;; i++ )
|
for ( int i = 0;; i++ )
|
||||||
|
{
|
||||||
|
int[] ali = al[i];
|
||||||
|
if ( ali == null )
|
||||||
|
break;
|
||||||
|
int lpi = lp[i];
|
||||||
|
if ( lpi < 4 << i )
|
||||||
{
|
{
|
||||||
int[] ali = al[i];
|
int currentId = ali[lpi];
|
||||||
if ( ali == null ) break;
|
if ( minIdx < 0 || currentId < minId )
|
||||||
int lpi = lp[i];
|
|
||||||
if ( lpi < ali.length )
|
|
||||||
{
|
{
|
||||||
int currentId = ali[lpi];
|
minIdx = i;
|
||||||
if ( minIdx < 0 || currentId < minId )
|
minId = currentId;
|
||||||
{
|
|
||||||
minIdx = i;
|
|
||||||
minId = currentId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( minIdx == -1 ) return null;
|
if ( minIdx == -1 )
|
||||||
|
return null;
|
||||||
|
|
||||||
int lp_minIdx = lp[minIdx]++;
|
int lp_minIdx = lp[minIdx]++;
|
||||||
Object[] vla_minIdx = vla[minIdx];
|
Object[] vla_minIdx = vla[minIdx];
|
||||||
V res =(V)vla_minIdx[lp_minIdx];
|
V res = (V) vla_minIdx[lp_minIdx];
|
||||||
vla_minIdx[lp_minIdx] = null;
|
vla_minIdx[lp_minIdx] = null;
|
||||||
size--;
|
size--;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a key value pair to the heap
|
* add a key value pair to the heap
|
||||||
*
|
*
|
||||||
* @param id the key to insert
|
* @param id
|
||||||
* @param value the value to insert object
|
* the key to insert
|
||||||
|
* @param value
|
||||||
|
* the value to insert object
|
||||||
*/
|
*/
|
||||||
public void add( int key, V value )
|
public void add( int key, V value )
|
||||||
{
|
{
|
||||||
isClear = false;
|
isClear = false;
|
||||||
size++;
|
size++;
|
||||||
|
|
||||||
// trivial shortcut if first array empty
|
if ( lp[0] == 0 )
|
||||||
if ( lp[1] == 1)
|
{
|
||||||
{
|
sortUp();
|
||||||
al[1][0] = key;
|
}
|
||||||
vla[1][0] = value;
|
int lp0 = lp[0];
|
||||||
lp[1] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// trivial shortcut if second array empty
|
|
||||||
if ( lp[2] > 0 )
|
|
||||||
{
|
|
||||||
int[] al2 = al[2];
|
|
||||||
Object[] vla2 = vla[2];
|
|
||||||
int key1;
|
|
||||||
Object val1;
|
|
||||||
if ( lp[2] == 2 )
|
|
||||||
{
|
|
||||||
key1 = al[1][0];
|
|
||||||
val1 = vla[1][0];
|
|
||||||
lp[1] = 1;
|
|
||||||
}
|
|
||||||
else // == 1
|
|
||||||
{
|
|
||||||
key1 = al2[1];
|
|
||||||
val1 = vla2[1];
|
|
||||||
}
|
|
||||||
lp[2] = 0;
|
|
||||||
if ( key1 < key )
|
|
||||||
{
|
|
||||||
al2[0] = key1;
|
|
||||||
vla2[0] = val1;
|
|
||||||
al2[1] = key;
|
|
||||||
vla2[1] = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
al2[1] = key1;
|
|
||||||
vla2[1] = val1;
|
|
||||||
al2[0] = key;
|
|
||||||
vla2[0] = value;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// put the new entry in the first array
|
int[] al0 = al[0];
|
||||||
al[0][0] = key;
|
Object[] vla0 = vla[0];
|
||||||
vla[0][0] = value;
|
|
||||||
|
|
||||||
pa[0] = 1;
|
|
||||||
pa[1] = 1;
|
|
||||||
pa[2] = 2;
|
|
||||||
|
|
||||||
// determine the first array big enough to take them all
|
|
||||||
int cnt = 4; // value count up to idx
|
|
||||||
int idx = 3;
|
|
||||||
int n = 4;
|
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
cnt += n-lp[idx];
|
if ( lp0 == 4 || key < al0[lp0] )
|
||||||
if ( cnt <= n ) break;
|
{
|
||||||
pa[idx++] = n;
|
al0[lp0-1] = key;
|
||||||
n <<= 1;
|
vla0[lp0-1] = value;
|
||||||
|
lp[0]--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
al0[lp0-1] = al0[lp0];
|
||||||
|
vla0[lp0-1] = vla0[lp0];
|
||||||
|
lp0++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( idx == MAXLISTS )
|
private void sortUp()
|
||||||
|
{
|
||||||
|
// determine the first array big enough to take them all
|
||||||
|
int cnt = 4; // value count up to idx
|
||||||
|
int idx = 1;
|
||||||
|
int n = 8;
|
||||||
|
int firstNonEmptyIdx = 0;
|
||||||
|
int nonEmptyCount = 1;
|
||||||
|
|
||||||
|
for ( ;; )
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException( "overflow" );
|
int nentries = n - lp[idx];
|
||||||
|
if ( nentries > 0 )
|
||||||
|
{
|
||||||
|
cnt += n - lp[idx];
|
||||||
|
nonEmptyCount++;
|
||||||
|
}
|
||||||
|
if ( cnt <= n )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
n <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create it if not existant
|
// create it if not existant
|
||||||
|
@ -152,112 +132,146 @@ public class SortedHeap<V>
|
||||||
|
|
||||||
int[] al_t = al[idx];
|
int[] al_t = al[idx];
|
||||||
Object[] vla_t = vla[idx];
|
Object[] vla_t = vla[idx];
|
||||||
int lp_t = lp[idx];
|
int tp = n-cnt; // target pointer
|
||||||
|
|
||||||
// shift down content if any
|
// now merge the contents of arrays 0...idx into idx
|
||||||
if ( lp_t < n )
|
while( nonEmptyCount > 1 )
|
||||||
{
|
{
|
||||||
System.arraycopy(al_t, lp_t, al_t, 0, n-lp_t);
|
int i = firstNonEmptyIdx;
|
||||||
System.arraycopy(vla_t, lp_t, vla_t, 0, n-lp_t);
|
int minId = al[i][lp[i]];
|
||||||
}
|
int minIdx = i;
|
||||||
lp[idx] = 0;
|
|
||||||
pa[idx] = n - lp_t;
|
|
||||||
|
|
||||||
|
for ( i++; i <= idx; i++ )
|
||||||
// now merge the contents of arrays 0...idx-1 into idx
|
|
||||||
while ( cnt > 0 )
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
while( pa[i] == lp[i] )
|
|
||||||
{
|
{
|
||||||
i++;
|
if ( 4 << i > lp[i] )
|
||||||
}
|
|
||||||
int maxId = al[i][pa[i]-1];
|
|
||||||
int maxIdx = i;
|
|
||||||
|
|
||||||
for ( i++; i<=idx; i++ )
|
|
||||||
{
|
|
||||||
int p = pa[i];
|
|
||||||
if ( p > lp[i] )
|
|
||||||
{
|
{
|
||||||
int currentId = al[i][p-1];
|
int currentId = al[i][lp[i]];
|
||||||
if ( currentId > maxId )
|
if ( currentId < minId )
|
||||||
{
|
{
|
||||||
maxIdx = i;
|
minIdx = i;
|
||||||
maxId = currentId;
|
minId = currentId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// current maximum found, copy to target array
|
// current minimum found, copy to target array
|
||||||
--n;
|
int sp = lp[minIdx]; // source-pointer
|
||||||
al[idx][n] = maxId;
|
al_t[tp] = minId;
|
||||||
vla[idx][n] = vla[maxIdx][pa[maxIdx]-1];
|
vla_t[tp++] = vla[minIdx][sp];
|
||||||
|
if ( minIdx != idx )
|
||||||
--cnt;
|
{
|
||||||
--pa[maxIdx];
|
vla[minIdx][sp] = null;
|
||||||
|
}
|
||||||
|
if ( ++lp[minIdx] == 4 << minIdx )
|
||||||
|
{
|
||||||
|
nonEmptyCount--;
|
||||||
|
if ( minIdx == firstNonEmptyIdx )
|
||||||
|
{
|
||||||
|
while( lp[firstNonEmptyIdx] == 4 << firstNonEmptyIdx )
|
||||||
|
{
|
||||||
|
firstNonEmptyIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lp[idx] = n;
|
|
||||||
while(--idx > 0) lp[idx] = al[idx].length;
|
// only one non-empty index left, so just copy the remaining entries
|
||||||
|
if ( firstNonEmptyIdx != idx ) // no self-copy needed
|
||||||
|
{
|
||||||
|
int[] al_s = al[firstNonEmptyIdx];
|
||||||
|
Object[] vla_s = vla[firstNonEmptyIdx];
|
||||||
|
int sp = lp[firstNonEmptyIdx]; // source-pointer
|
||||||
|
while( sp < 4 << firstNonEmptyIdx )
|
||||||
|
{
|
||||||
|
al_t[tp] = al_s[sp];
|
||||||
|
vla_t[tp++] = vla_s[sp];
|
||||||
|
vla_s[sp++] = null;
|
||||||
|
}
|
||||||
|
lp[firstNonEmptyIdx] = sp;
|
||||||
|
}
|
||||||
|
lp[idx] = n-cnt; // new target low pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
if ( !isClear )
|
if ( !isClear )
|
||||||
{
|
{
|
||||||
isClear = true;
|
isClear = true;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
// pointer array
|
lp = new int[MAXLISTS];
|
||||||
pa = new int[MAXLISTS];
|
|
||||||
|
|
||||||
lp = new int[MAXLISTS];
|
// allocate key lists
|
||||||
|
al = new int[MAXLISTS][];
|
||||||
|
al[0] = new int[4]; // make the first array
|
||||||
|
|
||||||
// allocate key lists
|
// same for the values
|
||||||
al = new int[MAXLISTS][];
|
vla = new Object[MAXLISTS][];
|
||||||
al[0] = new int[1]; // make the first arrays
|
vla[0] = new Object[4];
|
||||||
al[1] = new int[1];
|
|
||||||
al[2] = new int[2];
|
|
||||||
|
|
||||||
// same for the values
|
int n = 4;
|
||||||
vla = new Object[MAXLISTS][];
|
for ( int idx = 0; idx < MAXLISTS; idx++ )
|
||||||
vla[0] = new Object[1];
|
{
|
||||||
vla[1] = new Object[1];
|
lp[idx] = n;
|
||||||
vla[2] = new Object[2];
|
n <<= 1;
|
||||||
|
}
|
||||||
int n = 1;
|
}
|
||||||
lp[0] = 0;
|
|
||||||
for( int idx=1; idx < MAXLISTS; idx++ )
|
|
||||||
{
|
|
||||||
lp[idx] = n;
|
|
||||||
n <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<V> getExtract()
|
public List<V> getExtract()
|
||||||
{
|
{
|
||||||
int div = size / 1000 + 1;
|
int div = size / 1000 + 1;
|
||||||
|
|
||||||
ArrayList<V> res = new ArrayList<V>(size / div );
|
ArrayList<V> res = new ArrayList<V>( size / div );
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for ( int i=1;; i++ )
|
for ( int i = 1;; i++ )
|
||||||
|
{
|
||||||
|
int[] ali = al[i];
|
||||||
|
if ( ali == null )
|
||||||
|
break;
|
||||||
|
int lpi = lp[i];
|
||||||
|
Object[] vlai = vla[i];
|
||||||
|
int n = 4 << i;
|
||||||
|
while (lpi < n)
|
||||||
{
|
{
|
||||||
int[] ali = al[i];
|
if ( ( ++cnt ) % div == 0 )
|
||||||
if ( ali == null ) break;
|
|
||||||
int lpi = lp[i];
|
|
||||||
Object[] vlai = vla[i];
|
|
||||||
int n = ali.length;
|
|
||||||
while ( lpi < n )
|
|
||||||
{
|
{
|
||||||
if ( (++cnt) % div == 0 )
|
res.add( (V) vla[i][lpi] );
|
||||||
{
|
|
||||||
res.add( (V)vla[i][lpi] );
|
|
||||||
}
|
|
||||||
lpi++;
|
|
||||||
}
|
}
|
||||||
|
lpi++;
|
||||||
}
|
}
|
||||||
return res;
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
SortedHeap<String> sh = new SortedHeap<String>();
|
||||||
|
Random rnd = new Random();
|
||||||
|
for( int i = 0; i< 6; i++ )
|
||||||
|
{
|
||||||
|
int val = rnd.nextInt( 1000000 );
|
||||||
|
sh.add( val, "" + val );
|
||||||
|
val = rnd.nextInt( 1000000 );
|
||||||
|
sh.add( val, "" + val );
|
||||||
|
sh.popLowestKeyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
int lastval = 0;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
String s = sh.popLowestKeyValue();
|
||||||
|
if ( s == null ) break;
|
||||||
|
cnt ++;
|
||||||
|
int val = Integer.parseInt( s );
|
||||||
|
System.out.println( "popLowestKeyValue: " + val);
|
||||||
|
// Assert.assertTrue( "sorting test", val >= lastval );
|
||||||
|
lastval = val;
|
||||||
|
}
|
||||||
|
// Assert.assertTrue( "total count test", cnt == 100000 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue