2009-11-05 6 views
5

Estoy implementando una ventana deslizante sobre una secuencia de eventos, en Java. así que quiero una estructura de datos que me permite hacer lo siguiente:¿Alguna biblioteca de Java proporciona una implementación de cola de acceso aleatorio?

  1. añadir al final de la estructura de datos cuando se producen nuevos eventos;

  2. eliminar desde el principio de la estructura de datos cuando se procesan eventos antiguos;

  3. obtienen acceso aleatorio estándar (size(), get(i)) a los elementos de la estructura de datos; en general, operaciones típicas de "lectura" List;

  4. es eficiente para todas las operaciones anteriores;

  5. no tiene límites.

No se requiere otro acceso. Y no se requiere seguridad de hilo.

Actualmente estoy haciendo esto con un ArrayList, para poner todo en funcionamiento. Pero quiero algo más eficiente; el método remove(0) (2. arriba) es ineficiente con un ArrayList.

Los números 1. y 2. son operaciones estándar de estilo Queue. Sin embargo, las implementaciones de Queue en el JDK (como ArrayDeque) no permiten get(i) en 3.

Por lo tanto, me pregunto si hay algún bibliotecas por ahí que tienen este tipo de implementación, y son adecuado para uso comercial.

Si no es así, creo que voy a recurro a escribir mi propia ...

+0

Cómo relativamente frecuentes son estas operaciones? Es posible que deba cambiar algún espacio importante por tiempo, p. podría usar una lista enlazada cíclicamente con un índice para recuperación rápida (índice: Olvidé el nombre para esta estructura, un árbol binario de apuntadores a 0 y n/2, cada uno de los cuales almacena punteros al punto medio de su mitad, etc.) –

Respuesta

0

La única biblioteca que puedo pensar que implementaría una interfaz de este tipo sería un LinkedList pero francamente no estoy seguro de lo que el las características de rendimiento son

+0

Esto no permitirá un acceso aleatorio eficiente, llamando a get (i). – Calum

+0

No es bueno para el acceso aleatorio. –

+0

Muy cierto. Me interesaría ver lo que aparece aquí, ya que no estoy seguro de cómo se puede rodar eficazmente tanto el acceso aleatorio eficiente con el tipo de velocidad que se obtiene de una cola FIFO estándar de pantano ... – Jasoon

4

Parece una tarea para un Circular Buffer - mientras esté bien si la cola tiene una capacidad fija. Aunque no sé de ninguna implementación estándar. Pero aquí está a nice recipe to roll your own.

+0

Olvidé decir que no debería haber sido limitado, ahora he actualizado la pregunta. – Calum

+0

Puede aumentar la capacidad si es necesario, como por ejemplo el arraylist. Sin embargo, es costoso – sfussenegger

+0

Doblar una matriz en tamaño cuando se necesita más capacidad aún hace que la inserción se amortice a tiempo constante, por lo que es solo "costosa" si necesita garantías de latencia fija. La pregunta era sobre Java, donde GC es generalmente un problema mayor para la latencia impredecible que el doble del conjunto. Yo diría que un búfer circular es la respuesta correcta para los requisitos. –

3

Si tiene una matriz lo suficientemente grande, puede implementar una cola con una matriz básica, y simplemente use un índice como el encabezado de la lista, y use el operador de mod para que pueda envolver si es necesario.

Por lo tanto, básicamente tiene una matriz circular que admite las funciones de inserción y eliminación.

UPDATE:

Es una operación rápida para copiar una matriz a una matriz más grande, por lo que sólo se duplique en tamaño, tal vez, al conseguir cerca del final, y simplemente copiar la matriz, como un paso haciendo insertar. En general, todavía tendrá acceso muy rápido, ya que la norma no debería ser aumentar y copiar.

+0

Más específicamente, doblar una matriz en tamaño cuando se necesita más capacidad todavía hace que la inserción se amortice a tiempo constante. Este es un enfoque sensato. –

2

¿Qué tan rápido entran y salen los eventos de esta cola?

Por un lado, puede tener un búfer circular "suficientemente grande".

Si bien técnicamente es "limitado", puede hacerlo "ilimitado" cultivándolo según sea necesario.

De la misma manera, puede "achicarlo" en términos de capacidad general cuando está "en silencio".

Pero, para muchas aplicaciones, una memoria intermedia circular de capacidad de 100, 1000 o incluso 10000 elementos no tiene límites.

0

Simplemente lanzando esto como alternativa a la aplicación propia, por lo que lo tomo con un grano de sal: Dependiendo de la frecuencia con la que necesite el acceso aleatorio get(i) y qué rendimiento necesita de él (y qué tan grande es el tamaño de la cola generalmente), siempre puede usar ArrayDeque.toArray()[i] cuando necesite acceder a un elemento. El toArray() usa System.arraycopy() debajo de las cubiertas, lo que debería ser bastante rápido para tamaños pequeños de cola y uso ocasional. Ayudaría a comprender por qué necesita acceso aleatorio a una cola y con qué frecuencia es necesaria, posiblemente haya una manera diferente de implementar su algoritmo sin ella.

0

Un montón binomial puede tener O (1) inserto amortizado y O (log n) amortizado delete min; Creo que también puede tener O (log ** 2 n) acceso aleatorio amortizado. Queue-push insertaría el elemento en el montón, con números enteros sucesivos como claves.

Con un rbtree, puede hacer queue-push con O (log n) pesimista para todo el acceso insert, delete min y random. Esto se debe a que el árbol tendrá un conjunto contiguo de enteros como las claves, y el elemento k-ésimo de la cola será el elemento en el árbol con la clave k-ésima.

1

Si realmente debe ser ilimitado, algo así como ConcurrentSkipListMap puede ser útil, si asigna una secuencia de incremento a cada evento para utilizar como la clave en el mapa. Proporcionó métodos como pollFirst/LastEntry. Si puede sacrificar la naturaleza ilimitada, entonces un búfer en anillo puede ser lo que necesita.

3

Tengo este problema y trataron de resolverlo mediante la copia del código fuente de ArrayDeque y añadiendo algo como:

E get(index){ return elements[(head + index) % size];} 
+0

Gracias, también acabo de portar ArrayDeque para poder usarlo en Android API Nivel 8. Solo tuve que agregar el siguiente método: 'public E get (int index) {return elements [(head + index)% size()] ;} ' – gsingh2011

+1

En realidad, el código que publiqué dio como resultado un puntero nulo a veces. Este código funciona, pero no sé por qué: 'public E get (int index) {return elements [(head + index)% elements.length];}' – gsingh2011

+0

@ gsingh2011: Internamente, la cola está respaldada por una matriz con tamaño preasignado, que es 'elementos'. El 'elements.length' devuelve el tamaño de la matriz interna en lugar del' size() 'de la cola. – FuzzY

Cuestiones relacionadas