2015-08-02 37 views
5

La funzione seguente richiede due BitSets, crea una copia del primo (non deve essere sovrascritta), interseca la copia con il secondo (bit AND) e restituisce la cardinalità del risultato .Java più veloce per ottenere la cardinalità dell'intersezione BitSet

public int getIntersectionSize(BitSet bits1, BitSet bits2) { 
    BitSet copy = (BitSet) bits1.clone(); 
    copy.and(bits2); 
    return copy.cardinality(); 
} 

Sono interessato se questo codice può essere velocizzato? Questa funzione è chiamata miliardi di volte quindi anche un accelerazione in microsecondi ha senso, più sono curioso del codice più veloce possibile.

+0

Un'idea: si potrebbe provare a evitare di creare un nuovo BitSet che stai semplicemente buttando via. –

+0

Ulteriori informazioni richieste: quanto tempo impiega chiamare un miliardo di volte? E puoi cambiare il tuo algoritmo per non chiamarlo un miliardo di volte? –

+1

Non ho controllato le parti interne di BitSet ma potrebbe essere possibile fare tutto in una volta, invece di fare un 'and' e poi' cardinality' provare a contare la cardinalità ** while ** facendo 'e' manualmente ? –

risposta

1

Ecco una versione alternativa, ma non sono sicuro se è molto più veloce, dipende da nextSetBit.

public int getIntersectionsSize(BitSet bits1, BitSet bits2) { 
    int count = 0; 
    int i = bits1.nextSetBit(0); 
    int j = bits2.nextSetBit(0); 
    while (i >= 0 && j >= 0) { 
     if (i < j) { 
     i = bits1.nextSetBit(i + 1); 
     } else if (i > j) { 
     j = bits2.nextSetBit(j + 1); 
     } else { 
     count++; 
     i = bits1.nextSetBit(i + 1); 
     j = bits2.nextSetBit(j + 1); 
     } 
    } 
    return count; 
} 

Quanto sopra è la versione leggibile, si spera abbastanza buono per il compilatore, ma si potrebbe ottimizzare manualmente immagino:

public int getIntersectionsSize(BitSet bits1, BitSet bits2) { 
    int count = 0; 
    for (int i = bits1.nextSetBit(0), j = bits2.nextSetBit(0); i >= 0 && j >= 0;) { 
     while (i < j) { 
     i = bits1.nextSetBit(i + 1); 
     if (i < 0) 
      return count; 
     } 
     if (i == j) { 
     count++; 
     i = bits1.nextSetBit(i + 1); 
     } 
     while (j < i) { 
     j = bits2.nextSetBit(j + 1); 
     if (j < 0) 
      return count; 
     } 
     if (i == j) { 
     count++; 
     j = bits2.nextSetBit(j + 1); 
     } 
    } 
    return count; 
} 
+0

@BrandonMcHomery Se si desidera utilizzare la funzionalità di BitSet, penso che la tua versione sia probabilmente la migliore che puoi ottenere. Quanto sopra potrebbe essere buono per BitSet "sparsi". Posso cancellarlo se vuoi. – maraca

+1

@maraca questo sarà più lento perché stai andando passo dopo passo, internamente 'BitSet' lavora per parola quindi il numero di operazioni per dire 'e' è molto più piccolo. –

+0

@MateuszDymczyk yes, potrebbe essere ancora migliore per i bitSet "sparsi" (la maggior parte dei bit è falso) o no? – maraca

2

Se avete intenzione di utilizzare ogni BitSet più volte, potrebbe essere utile creare un array long corrispondente a ogni BitSet. Per ogni BitSet:

long[] longs = bitset.toLongArray(); 

quindi è possibile utilizzare il seguente metodo, che evita il sovraccarico di creare un clonato BitSet. (Ciò presuppone che entrambi gli array abbiano la stessa lunghezza).

int getIntersectionSize(long[] bits1, long[] bits2) { 
    int nBits = 0; 
    for (int i=0; i<bits1.length; i++) 
     nBits += Long.bitCount(bits1[i] & bits2[i]); 
    return nBits; 
}