2010-06-15 88 views
42

Me gustaría un método que toma List<T> donde T implementa Comparable y devuelve true o false dependiendo de si la lista está ordenada o no.¿Cómo determinar si una lista está ordenada en Java?

¿Cuál es la mejor manera de implementar esto en Java? Es obvio que genéricos y comodines están destinados a ser capaces de manejar tales cosas fácilmente, pero me estoy enredando.

También sería bueno tener un método análogo para verificar si la lista está en orden inverso.

+0

¿Alguna posibilidad de que pueda utilizar una colección ordenada? O simplemente llame a .Sort() según sea necesario. – Juliet

+0

El propósito de esto es para probar, entonces no. –

+0

se supone que la lista está en orden ascendente o descendente? –

Respuesta

86

Guava proporciona esta funcionalidad a través de su impresionante clase Ordering. Un Ordering es un Comparator ++. En este caso, si usted tiene una lista de algún tipo que implementa Comparable, se podría escribir:

boolean sorted = Ordering.natural().isOrdered(list); 

Esto funciona para cualquier Iterable, no sólo List, y que puede manejar null s fácilmente especificando si deben venir antes o después de cualquier otro null elementos no:

Ordering.natural().nullsLast().isOrdered(list); 

también, ya que ha mencionado que le gustaría ser capaz de comprobar el orden inverso, así como de costumbre, que se llevaría a cabo como:

Ordering.natural().reverse().isOrdered(list); 

Java 8 usuarios: Utilice el equivalente Comparators#isInOrder(Iterable) lugar, ya que el resto de pedidos es en su mayoría obsoletos (como se explica en la clase documentation).

+8

Y también está 'isStrictlyOrdered()' si quiere asegurarse de que no haya duplicados. –

+9

+1 para señalar el código existente para que las personas dejen de reinventar las cosas y comiencen a hacer cosas nuevas. –

+0

¿Puedes mostrar un ejemplo de esto si no hay un orden natural y quieres pasar un 'Comparador'? Creo que eso es para lo que 'Ordering.from' es:" Devuelve un pedido basado en una instancia de comparador existente. Tenga en cuenta que no es necesario crear una nueva clase interna anónima que implemente Comparator solo para pasarlo aquí. En su lugar, simplemente subclass Ordering and implementar su método de comparación directamente ". –

5

Para comprobar si una lista o cualquier estructura de datos para esa materia es una tarea que solo toma O (n) tiempo. Simplemente itere sobre la lista usando la interfaz Iterator y ejecute los datos (en su caso ya lo tiene listo como un tipo de Comparable) de principio a fin y puede encontrar si está ordenado o no fácilmente

+1

Curiosamente, su algoritmo es en realidad O (1) tiempo esperado para listas razonablemente aleatorias. – mikera

+1

Sería O (n) en el peor de los casos (cuando la lista está realmente ordenada). – Jesper

+4

-1 dado que el asker ha indicado que se está "enredado" en cuestiones de implementación como genéricos y comodines, creo que esta respuesta solo le está diciendo cosas que ya sabe. –

1

Esto es un operación que tomará O (n) el tiempo (peor caso). Necesitará manejar dos casos: donde la lista está ordenada en orden descendente y donde la lista está ordenada en orden ascendente.

Deberá comparar cada elemento con el siguiente elemento mientras se asegura de que la orden se conserve.

16

Fácil:

List tmp = new ArrayList(myList); 
Collections.sort(tmp); 
boolean sorted = tmp.equals(myList); 

o (si los elementos son comparables):

Object prev; 
for(Object elem : myList) { 
    if(prev != null && prev.compareTo(elem) > 0) { 
     return false; 
    } 
    prev = elem; 
} 
return true; 

o (si los elementos no son comparables):

Object prev; 
for(Object elem : myList) { 
    if(prev != null && myComparator.compare(prev,elem) > 0) { 
     return false; 
    } 
    prev = elem; 
} 
return true; 

Las implementaciones fracasan por listas que contienen valores nulos. Tienes que agregar cheques apropiados en este caso.

+0

Collections.sort requeriría que los elementos de la lista ya sean comparables, y eso era una estipulación en la pregunta en cualquier caso. – Yishai

+3

Creo que a su primer ejemplo le falta una línea, ya que 'tmp' no está lleno. –

+1

El primer ejemplo también es bastante inútil para lo que hace, y los objetos en el segundo deben ser comparables. – ColinD

3

Simplemente use el iterador para revisar los contenidos del List<T>.

public static <T extends Comparable> boolean isSorted(List<T> listOfT) { 
    T previous = null; 
    for (T t: listOfT) { 
     if (previous != null && t.compareTo(previous) < 0) return false; 
     previous = t; 
    } 
    return true; 
} 
+3

Esto continúa porque 'anterior' nunca se establecerá. Ver la respuesta de Daniel para el flujo correcto. – BalusC

+0

Vaya, gracias por señalar eso. Lo arreglé. (@BalusC) – jjnguy

+0

Tendría que estar limitado a '' también, por supuesto. – ColinD

2

Esto es lo que haría:

public static <T extends Comparable<? super T>> boolean isSorted(List<T> list) { 
    if (list.size() != 0) { 
     ListIterator<T> it = list.listIterator(); 
     for (T item = it.next(); it.hasNext(); item = it.next()) { 
      if (it.hasPrevious() && it.previous().compareTo(it.next()) > 0) { 
       return false; 
      } 
     } 

    } 
    return true; 
} 
22

Aquí es un método genérico que va a hacer el truco:

public static <T extends Comparable<? super T>> 
     boolean isSorted(Iterable<T> iterable) { 
    Iterator<T> iter = iterable.iterator(); 
    if (!iter.hasNext()) { 
     return true; 
    } 
    T t = iter.next(); 
    while (iter.hasNext()) { 
     T t2 = iter.next(); 
     if (t.compareTo(t2) > 0) { 
      return false; 
     } 
     t = t2; 
    } 
    return true; 
} 
0

Una aplicación sencilla en arrays:

public static <T extends Comparable<? super T>> boolean isSorted(T[] a, int start, int end) { 
    while (start<end) { 
     if (a[start].compareTo(a[start+1])>0) return false; 
     start++; 
    } 
    return true; 
} 

la conversión de listas:

public static <T extends Comparable<? super T>> boolean isSorted(List<T> a) { 
    int length=a.size(); 
    if (length<=1) return true; 

    int i=1; 
    T previous=a.get(0); 
    while (i<length) { 
     T current=a.get(i++); 
     if (previous.compareTo(current)>0) return false; 
     previous=current; 
    } 
    return true; 
} 
+1

p.s. tenga en cuenta que la implementación está diseñada deliberadamente para evitar asignar un iterador o hacer múltiples llamadas para obtener. Esto está diseñado para el caso común donde está usando una ArrayList, para la implementación de otras listas probablemente sea mejor usar el iterador. – mikera

+0

Una cosa que se podría hacer en este caso sería verificar si la 'Lista' implementa' RandomAccess' y usar esta implementación si es así y una implementación 'Iterator' si no es así. No querrás usar esto con una 'LinkedList' tal como está. – ColinD

+0

@ColinD ¡gran idea! Supongo que podría hacer esto para que también lo detecte en compilación – mikera

2
private static <T extends Comparable<? super T>> boolean isSorted(List<T> array){ 
    for (int i = 0; i < array.size()-1; i++) { 
     if(array.get(i).compareTo(array.get(i+1))> 0){ 
      return false; 
     } 
    } 
    return true; 
} 

zzzzz no estoy seguro de lo que ustedes están haciendo, pero esto se puede hacer en bucle simple.

+0

, la implementación de la biblioteca en la respuesta aceptada (Guava) es esencialmente esta: https://github.com/google/guava/blob/ e7700e6f78d9594d1ee37d43bf4e0aa1e58b4e7a/guava/src/com/google/common/collect/Ordering.java # L895 Pero siempre es mejor mantener la base de código pequeña en lugar de volver a implementar cosas que una biblioteca puede proporcionarle. –

+0

Esto es mucho mejor que ordenar la matriz y comprobar si son iguales. – ShellFish

0

Si lo necesita para probar la unidad, puede usar AssertJ. Contiene una afirmación para comprobar si se ordena una lista:

List<String> someStrings = ... 
assertThat(someStrings).isSorted(); 

También hay un método alternativo isSortedAccordingTo que toma un comparador en caso de que desee utilizar un comparador personalizado para la clasificación.

7

Si está utilizando Java 8, las secuencias pueden ser de ayuda.

list.stream().sorted().collect(Collectors.toList()).equals(list); 

Este código será ordenar la lista fuera de lugar y recoger sus elementos en otra lista, que luego se compara con la lista inicial. La comparación será exitosa si ambas listas contienen los mismos elementos en posiciones iguales.

Este método puede no ser la solución de más rápido rendimiento, pero es la más fácil de implementar, que no implica marcos de terceros.

+1

Bueno ... obviamente no me ayudó a usar Java 6 en 2010, pero esta es una buena adición. –

+0

Mucho menos eficaz que la solución ideal sin asignación y sin clasificación. – Vadzim

+0

De acuerdo con Java 8 documentos, Collectors.toList(); No hay garantías sobre el tipo, mutabilidad, serializabilidad o seguridad de subprocesos de la {@code List} devuelta; Debería usar un proveedor de ArrayList – danidacar

Cuestiones relacionadas