2012-05-09 15 views
5

He escrito este código para comprobar qué bits son el de un entero (si está representado en binario) en Java:Qué bit está activado por un entero en Java

public static List<String> list(int val) 
{ 
    List<String> dummyList = new ArrayList<String>(); 

    int bit = 1; 
    int x; 

    for(int i=0; i<32; i++) 
    { 
     x = bit; 
     if((x&val)!=0) 
      dummyList.add(String.valueOf(i+1)); 
     bit = bit << 1; 
    } 

    return dummyList; 
} 

El código escrito anterior funciona correctamente. Pero tiene un bucle que se ejecuta 32 veces (en Java el entero tiene 32 bits de longitud). Quiero minimizar esta complejidad. Por favor comparte la mejor solución. Gracias por adelantado.

+4

¿Qué estás haciendo * con esa lista? ¿Tiene algún indicio de que esto realmente le esté causando problemas? –

+2

Bueno, poner un límite en el número de bucles con "val"? Usted conoce el límite si conoce el int – keyser

+2

¿Qué hay de malo en hacer que se repita 32 veces? Dado que hay 32 bits, me parece bastante razonable que para verificar cada bit, deberías repetir 32 veces. –

Respuesta

0

La complejidad es O (1), por lo que no hay mucho que "minimizar" allí.

Su código está bien ... aquí se refactoriza un poco.

public static List<String> list(int val) { 
    List<String> dummyList = new ArrayList<String>(); 
    for (int i = 0; i < 32; i++) 
     if ((1 << i & val) != 0) 
      dummyList.add("" + (i+1)); 
    return dummyList; 
} 

Por cierto, ¿ha considerado el uso de un BitSet?

+0

Gracias por el fragmento de código. No he considerado BitSet. ¿Cuál es el uso de BitSet? – Comet

+1

No puedo explicarlo mejor que los documentos API ;-) – aioobe

+0

No hay problema. Verá la documentación. :) – Comet

0

32 bucles suena bien para esta aplicación. Puede usar un StringBuffer en lugar de una lista si desea recopilar los dígitos más rápido.

public static String list(int val) 
{ 
    StringBuffer dummyList = new StringBuffer(); 

    int bit = 1; 
    int x; 

    for(int i=0; i<32; i++) 
    { 
     x = bit; 
     dummyList.append((x&val) ? '1' : '0'); 
     bit = bit << 1; 
    } 

    return dummyList.toString(); 
} 
+0

Gracias por el fragmento de código y por su sugerencia de utilizar StringBuffer. Pero para un procesamiento posterior, necesitaba hacer uso de métodos ya definidos en la clase List, por eso utilicé List <>. – Comet

+0

¿Está tratando de reducir la complejidad algorítmica o el tiempo del reloj de pared? Si realiza algunas pruebas, es posible que sus suposiciones sobre lo que es más rápido sean incorrectas. Depende de lo que quiera que sea el formato de salida de su función. Me pregunto si quizás estás tratando de poner los identificadores de archivo en un Mapa, en cuyo caso podría ser una mejor idea extender el manejador de archivo con un código hash personalizado y usar un HashMap. Cuéntanos más acerca de lo que intentas hacer y por qué :) – alexg

+0

Tengo un archivo (digamos X) que contiene ~ 3000 valores uno en cada línea. Hay más de 2000 archivos (por ejemplo, Y) que consisten en esos valores. Para mi aplicación, tengo que averiguar qué valores son comunes entre dos archivos. Debido a que el conjunto de valores es grande, no es factible verificar uno por uno. Entonces hice el preprocesamiento. Inicialmente indexé valores en el archivo X de 1 a 3000. Luego hice grupos de 30 valores (por ejemplo, 0-29 es el grupo 1, 30-59 grupo 2, etc.). Entonces, en lugar de escribir valores en Y, escribí en el formato (). – Comet

0

Mejorar O(1) código parece trivial, pero este código es una ligera mejora:

public static List<String> list(int val) { 
    List<String> dummyList = new ArrayList<String>(); 
    for (int i=0; val!=0 && i<32; ++i){ 
     if ((1 << i & val) != 0) { 
      dummyList.add("" + (i+1)); 
      val &= val -1; // unset the last set bit (current bit) 
     }     // causes loop to end early when all bits are counted 
    } 
    return dummyList; 

En lugar de hacer todas las comparaciones de 32 bits, este código terminará tan pronto como el último bit se ha contado. Es mucho más eficiente para enteros que están escasamente poblados con 1 sy no menos eficiente para enteros que están muy poblados.

0

Dado que conoce la longitud exacta del número entero, le recomendaría usar un bool[] en su lugar. Sin embargo, no hay mucho que puedas hacer sobre la complejidad. Es lo más rápido que puede y el JIT probablemente va a desenrollar el circuito de este código de todos modos.

public static bool[] list(int val) 
{ 
    bool[] a = new bool[32]; 
    for(int i=0; i<32; i++) 
    { 
     a[i] = ((1 << i) & val) != 0; 
    } 
    return a; 
} 
1

Puede utilizar una máscara de bits para intentar reducir los tiempos a través del ciclo. Agrega algunas operaciones pero potencialmente hacer la mitad del bucle:.

public static List<String> list(int val) { 
    List<String> dummyList = new ArrayList<String>(); 
    int loop = 32; 

    // Mask the 16 MSB if all are zero only loop on the 16 LSB 
    if((val & 0xFFFF0000) == 0){ 
     loop = 16; 
    } 

    int bit = 1; 
    int x; 

    for (int i = 0; i < loop; i++) { 
     x = bit; 
     if ((x & val) != 0) { 
      dummyList.add(String.valueOf(i + 1)); 
     } 
     bit <<= 1; 
    } 

    return dummyList; 
} 

Potencialmente, esto podría aumentar el tiempo en función de los datos que entran

También puede reducir el bucle a la mitad para hacer dos bits a la vez:

public static List<String> list(int val) { 
    List<String> dummyList = new ArrayList<String>(); 

    int bit = 3; 
    int x; 

    for (int i = 0; i < 32; i += 2) { 
     x = (bit & val); 
     switch (x) { 
      case 1: 
       dummyList.add(String.valueOf(i + 1)); 
       break; 
      case 2: 
       dummyList.add(String.valueOf(i+2)); 
       break; 
      case 3: 
       dummyList.add(String.valueOf(i+1)); 
       dummyList.add(String.valueOf(i+2)); 
       break; 
      default: 
     } 
     val >>= 2; 
    } 

    return dummyList; 
} 
Cuestiones relacionadas