Respostas:
Isso chega muito tarde, mas há uma classe no JDK apenas com a finalidade de ter uma lista classificada. É nomeado (um pouco fora de ordem com as outras Sorted*
interfaces) " java.util.PriorityQueue
". Ele pode classificar Comparable<?>
s ou usar umComparator
.
A diferença com o List
uso ordenado Collections.sort(...)
é que isso manterá uma ordem parcial o tempo todo, com o desempenho de inserção O (log (n)), usando uma estrutura de dados de heap, enquanto a inserção em um ordenado ArrayList
será O (n) (ou seja, usando pesquisa binária e mover).
No entanto, ao contrário de a List
, PriorityQueue
não suporta acesso indexado ( get(5)
), a única maneira de acessar itens em um heap é retirá-los, um de cada vez (portanto, o nome PriorityQueue
).
TreeMap e TreeSet fornecerão uma iteração sobre o conteúdo em ordem classificada. Ou você pode usar um ArrayList e usar Collections.sort () para classificá-lo. Todas essas classes estão em java.util
Se você deseja manter uma lista classificada que você modifica frequentemente (ou seja, uma estrutura que, além de ser classificada, permite duplicatas e cujos elementos podem ser referenciados com eficiência pelo índice), use um ArrayList, mas quando precisar inserir um elemento , sempre use Collections.binarySearch () para determinar o índice no qual você adiciona um determinado elemento. O último método informa o índice que você precisa inserir para manter sua lista na ordem classificada.
Use a classe TreeMultiset do Google Guava . O Goiaba possui uma API espetacular de coleções.
Um problema ao fornecer uma implementação de List que mantém a ordem classificada é a promessa feita nos JavaDocs do add()
método.
List
sempre adiciona no final.
Existem algumas opções. Sugiro TreeSet se você não quiser duplicatas e os objetos que você está inserindo são comparáveis.
Você também pode usar os métodos estáticos da classe Collections para fazer isso.
Consulte Coleções # sort (java.util.List) e TreeSet para obter mais informações.
Se você quiser apenas classificar uma lista, use qualquer tipo de Lista e use Collections.sort () . Se você deseja garantir que os elementos da lista sejam exclusivos e sempre classificados, use um SortedSet .
O que eu fiz foi implementar a List com uma instância interna com todos os métodos delegados.
public class ContactList implements List<Contact>, Serializable {
private static final long serialVersionUID = -1862666454644475565L;
private final List<Contact> list;
public ContactList() {
super();
this.list = new ArrayList<Contact>();
}
public ContactList(List<Contact> list) {
super();
//copy and order list
List<Contact>aux= new ArrayList(list);
Collections.sort(aux);
this.list = aux;
}
public void clear() {
list.clear();
}
public boolean contains(Object object) {
return list.contains(object);
}
Depois, implementei um novo método "putOrdered", que é inserido na posição correta se o elemento não existir ou substituir apenas no caso de existir.
public void putOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
list.add(index, contact);
}else{
list.set(index, contact);
}
}
Se você deseja permitir elementos repetidos, basta implementar addOrdered (ou ambos).
public void addOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
}
list.add(index, contact);
}
Se você deseja evitar inserções, também pode lançar uma exceção de operação não suportada nos métodos "adicionar" e "definir".
public boolean add(Contact object) {
throw new UnsupportedOperationException("Use putOrdered instead");
}
... e também É preciso ter cuidado com os métodos ListIterator, pois eles podem modificar sua lista interna. Nesse caso, você pode retornar uma cópia da lista interna ou lançar uma exceção novamente.
public ListIterator<Contact> listIterator() {
return (new ArrayList<Contact>(list)).listIterator();
}
List
contrato. Talvez seja melhor implementar apenas Collection
. E se ContactList
for classificado, contains()
poderá ser implementado usando binarySearch
também para ser mais eficiente.
A maneira mais eficiente de implementar uma lista classificada como você deseja seria implementar um skiplist indexável como aqui: Wikipedia: skiplist indexável . Permitiria ter inserções / remoções em O (log (n)) e permitiria ter acesso indexado ao mesmo tempo. E também permitiria duplicatas.
O skiplist é uma estrutura de dados bastante interessante e, eu diria, subestimada. Infelizmente, não há implementação de skiplist indexada na biblioteca base Java, mas você pode usar uma das implementações de código aberto ou implementá-lo você mesmo. Existem implementações regulares do Skiplist como ConcurrentSkipListSet e ConcurrentSkipListMap
TreeSet não funcionaria porque eles não permitem duplicatas e não fornecem o método para buscar o elemento na posição específica. PriorityQueue não funcionaria porque não permite buscar elementos em uma posição específica, que é um requisito básico para uma lista. Eu acho que você precisa implementar seu próprio algoritmo para manter uma lista classificada em Java com tempo de inserção O (logn), a menos que você não precise de duplicatas. Talvez uma solução possa estar usando um TreeMap, onde a chave é uma subclasse do item, substituindo o método equals, para que duplicatas sejam permitidas.
Você pode tentar resolver essas tarefas com o LambdaJ se estiver usando versões anteriores do java 8. Você pode encontrá-lo aqui: http://code.google.com/p/lambdaj/
Aqui você tem um exemplo:
Classificar Iterativo
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
Classificar com LambdaJ
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
É claro que esse tipo de beleza afeta o desempenho (em média duas vezes), mas você consegue encontrar um código mais legível?
Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
-(p1.getAge().compareTo(p2.getAge()))
O problema com o PriorityQueue é que ele é copiado por uma matriz simples, e a lógica que coloca os elementos em ordem é feita pelos itens "fila [2 * n + 1] e fila [2 * (n + 1)]" ". Funciona muito bem se você simplesmente puxa da cabeça, mas a torna inútil se você estiver tentando chamar o .toArray em algum momento.
Eu resolvo esse problema usando com.google.common.collect.TreeMultimap, mas forneço um Comparador personalizado para os valores, agrupados em um Pedido, que nunca retorna 0.
ex. para o dobro:
private static final Ordering<Double> NoEqualOrder = Ordering.from(new Comparator<Double>() {
@Override
public int compare(Double d1, Double d2)
{
if (d1 < d2) {
return -1;
}
else {
return 1;
}
}
});
Dessa forma, eu obtenho os valores em ordem quando chamo .toArray () e também tenho duplicatas.
O que você quer é uma árvore de pesquisa binária. Ele mantém a ordem classificada e oferece acesso logarítmico para pesquisas, remoções e inserções (a menos que você tenha uma árvore degenerada - ela é linear). É muito fácil de implementar e você pode fazê-lo implementar a interface de lista, mas o acesso ao índice fica complicado.
A segunda abordagem é ter uma implementação ArrayList e, em seguida, uma classificação de bolha. Como você está inserindo ou removendo um elemento de cada vez, os tempos de acesso para inserções e remoções são lineares. As pesquisas são constantes logarítmicas e de acesso ao índice (os tempos podem ficar diferentes para o LinkedList). O único código que você precisa é de 5, talvez 6 linhas de classificação de bolhas.
Você pode usar Arraylist e Treemap, pois disse que deseja valores repetidos e não pode usar o TreeSet, embora ele também esteja classificado, mas é necessário definir o comparador.
Para Set, você pode usar o TreeSet. TreeSet ordena seus elementos com base em uma ordem natural ou em qualquer ordem de classificação passada para o Comparável para esse objeto em particular. Para o mapa, use o TreeMap. O TreeMap fornece a classificação das chaves. Para adicionar um objeto como uma chave ao TreeMap, essa classe deve implementar uma interface comparável que, por sua vez, força a implementação do método compare to () que contém a definição da ordem de classificação. http://techmastertutorial.in/java-collection-impl.html
Use o método sort () para classificar a lista como abaixo:
List list = new ArrayList();
//add elements to the list
Comparator comparator = new SomeComparator();
Collections.sort(list, comparator);
Para referência, consulte o link: http://tutorials.jenkov.com/java-collections/sorting.html
Use o TreeSet
que fornece elementos em ordem classificada. OU use Collection.sort()
para classificação externa com Comparator()
.
import java.util.TreeSet;
public class Ass3 {
TreeSet<String>str=new TreeSet<String>();
str.add("dog");
str.add("doonkey");
str.add("rat");
str.add("rabbit");
str.add("elephant");
System.out.println(str);
}
com o Java 8 Comparator, se quisermos classificar a lista, aqui estão as 10 cidades mais populosas do mundo e queremos classificá-la por nome, conforme relatado pela Time. Osaka, Japão. ... Cidade do México, México. ... Pequim, China. ... São Paulo, Brasil. ... Mumbai, índia. ... Xangai, China. ... Delhi, Índia. ... Tóquio, Japão.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortCityList {
/*
* Here are the 10 most populated cities in the world and we want to sort it by
* name, as reported by Time. Osaka, Japan. ... Mexico City, Mexico. ...
* Beijing, China. ... São Paulo, Brazil. ... Mumbai, India. ... Shanghai,
* China. ... Delhi, India. ... Tokyo, Japan.
*/
public static void main(String[] args) {
List<String> cities = Arrays.asList("Osaka", "Mexico City", "São Paulo", "Mumbai", "Shanghai", "Delhi",
"Tokyo");
System.out.println("Before Sorting List is:-");
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(String.CASE_INSENSITIVE_ORDER) & Sorting List is:-");
cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(Comparator.naturalOrder()) & Sorting List is:-");
cities.sort(Comparator.naturalOrder());
System.out.println(cities);
}
}
Classificando um ArrayList de acordo com os critérios definidos pelo usuário.
Classe de modelo
class Student
{
int rollno;
String name, address;
public Student(int rollno, String name, String address)
{
this.rollno = rollno;
this.name = name;
this.address = address;
}
public String toString()
{
return this.rollno + " " + this.name + " " + this.address;
}
}
Classe de classificação
class Sortbyroll implements Comparator<Student>
{
public int compare(Student a, Student b)
{
return a.rollno - b.rollno;
}
}
Classe principal
class Main
{
public static void main (String[] args)
{
ArrayList<Student> ar = new ArrayList<Student>();
ar.add(new Student(111, "bbbb", "london"));
ar.add(new Student(131, "aaaa", "nyc"));
ar.add(new Student(121, "cccc", "jaipur"));
System.out.println("Unsorted");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
Collections.sort(ar, new Sortbyroll());
System.out.println("\nSorted by rollno");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
}
}
Resultado
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc