【发布时间】:2010-09-29 19:09:24
【问题描述】:
我是 Java 初学者。请建议可以/应该使用哪些集合来维护 Java 中的排序列表。我试过Map 和Set,但它们不是我想要的。
【问题讨论】:
标签: java sorting collections
我是 Java 初学者。请建议可以/应该使用哪些集合来维护 Java 中的排序列表。我试过Map 和Set,但它们不是我想要的。
【问题讨论】:
标签: java sorting collections
这来得太晚了,但是 JDK 中有一个类只是为了有一个排序列表。它被命名为“java.util.PriorityQueue”(与其他Sorted* 接口有点乱)。它可以对Comparable<?>s 或使用Comparator 进行排序。
与使用Collections.sort(...) 排序的List 的区别在于,这将始终保持偏序,具有O(log(n)) 插入性能,通过使用堆数据结构,而插入排序ArrayList 将是 O(n)(即,使用二分查找和移动)。
但是,与List 不同,PriorityQueue 不支持索引访问 (get(5)),访问堆中项目的唯一方法是一次取出一个(因此名称为PriorityQueue)。
【讨论】:
TreeMap 和 TreeSet 将按排序顺序为您提供对内容的迭代。或者您可以使用 ArrayList 并使用 Collections.sort() 对其进行排序。所有这些类都在 java.util 中
【讨论】:
如果您想维护一个排序列表,您将经常修改(即,除了排序之外,还允许重复并且其元素可以有效地由索引引用),然后使用 ArrayList 但当您需要插入元素时,请始终使用 Collections.binarySearch() 来确定添加给定元素的索引。后一种方法告诉您需要插入的索引,以使您的列表保持排序。
【讨论】:
使用 Google Guava 的 TreeMultiset 类。 Guava 有一个壮观的集合 API。
提供维护排序顺序的 List 实现的一个问题是在 add() 方法的 JavaDocs 中做出的承诺。
【讨论】:
List 始终添加在末尾的要求。
有几个选项。如果您不想重复并且您插入的对象具有可比性,我建议使用 TreeSet。
您也可以使用 Collections 类的静态方法来执行此操作。
请参阅Collections#sort(java.util.List) 和TreeSet 了解更多信息。
【讨论】:
如果您只想对列表进行排序,请使用任何类型的 List 并使用 Collections.sort()。如果您想确保列表中的元素是唯一的并且始终排序,请使用SortedSet。
【讨论】:
我所做的是实现 List 具有一个内部实例和所有委托的方法。
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);
}
之后,我实现了一个新方法“putOrdered”,如果元素不存在则插入到适当的位置,或者以防万一它存在时替换。
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);
}
}
如果你想允许重复元素,只需实现 addOrdered 代替(或两者)。
public void addOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
}
list.add(index, contact);
}
如果您想避免插入,您还可以在“add”和“set”方法上抛出不受支持的操作异常。
public boolean add(Contact object) {
throw new UnsupportedOperationException("Use putOrdered instead");
}
...而且您必须小心使用 ListIterator 方法,因为它们可能会修改您的内部列表。在这种情况下,您可以返回内部列表的副本或再次抛出异常。
public ListIterator<Contact> listIterator() {
return (new ArrayList<Contact>(list)).listIterator();
}
【讨论】:
List合约。也许最好只实现Collection。而如果ContactList被排序,那么contains()也可以使用binarySearch来实现,效率更高。
实现您想要的排序列表的最有效方法是实现一个可索引的跳过列表,如下所示:Wikipedia: Indexable skiplist。 它将允许在 O(log(n)) 中进行插入/删除,并允许同时进行索引访问。它还允许重复。
Skiplist 是一种非常有趣的数据结构,我会说它被低估了。 不幸的是,Java 基础库中没有索引的跳过列表实现,但您可以使用开源实现之一或自己实现它。有常规的 Skiplist 实现,例如 ConcurrentSkipListSet 和 ConcurrentSkipListMap
【讨论】:
TreeSet 不起作用,因为它们不允许重复,而且它们不提供在特定位置获取元素的方法。 PriorityQueue 不起作用,因为它不允许在特定位置获取元素,这是列表的基本要求。 我认为您需要实现自己的算法来维护具有 O(logn) 插入时间的 Java 中的排序列表,除非您不需要重复项。 也许解决方案可能是使用 TreeMap ,其中键是覆盖 equals 方法的项目的子类,以便允许重复。
【讨论】:
如果您使用的是 java 8 的早期版本,您可以尝试使用 LambdaJ 解决这些任务。您可以在此处找到它:http://code.google.com/p/lambdaj/
这里有一个例子:
排序迭代
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());
}
});
使用 LambdaJ 排序
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
当然,有这种美感对性能有影响(平均2倍),但是你能找到更可读的代码吗?
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()))
PriorityQueue 的问题在于它是由一个简单的数组支持的,按顺序获取元素的逻辑是由“queue[2*n+1] 和 queue[2*(n+1)] “东西。如果你只是从头上拉,它会很好用,但如果你试图在某个时候调用 .toArray ,它就会变得毫无用处。
我通过使用 com.google.common.collect.TreeMultimap 解决了这个问题,但是我为值提供了一个自定义比较器,包装在 Ordering 中,永远不会返回 0。
例如。双倍:
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;
}
}
});
这样我在调用 .toArray() 时按顺序获取值,并且也有重复。
【讨论】:
对于 Set,您可以使用 TreeSet。 TreeSet 根据自然排序或传递给该特定对象的 Comparable 的任何排序顺序对其元素进行排序。 对于地图,请使用 TreeMap。 TreeMap 提供对键的排序。要将对象作为键添加到 TreeMap,该类应实现可比较接口,该接口又强制实现包含排序顺序定义的 compare to() 方法。 http://techmastertutorial.in/java-collection-impl.html
【讨论】:
你想要的是一个二叉搜索树。它保持排序顺序,同时为搜索、删除和插入提供对数访问(除非你有一个退化的树 - 然后它是线性的)。它很容易实现,你甚至可以让它实现 List 接口,但是索引访问变得复杂了。
第二种方法是先使用 ArrayList,然后再使用冒泡排序实现。因为您一次插入或删除一个元素,所以插入和删除的访问时间是线性的。搜索是对数和索引访问常量(对于 LinkedList,时间可能会有所不同)。您需要的唯一代码是 5 行,可能是 6 行冒泡排序。
【讨论】:
你可以使用 Arraylist 和 Treemap,正如你所说的你想要重复的值,然后你不能使用 TreeSet,虽然它也是排序的,但是你必须定义比较器。
【讨论】:
使用 sort() 方法对列表进行如下排序:
List list = new ArrayList();
//add elements to the list
Comparator comparator = new SomeComparator();
Collections.sort(list, comparator);
参考链接: http://tutorials.jenkov.com/java-collections/sorting.html
【讨论】:
使用TreeSet 以排序顺序给出元素。或使用Collection.sort() 与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);
}
【讨论】:
使用 Java 8 比较器,如果我们想对列表进行排序,那么这里是世界上人口最多的 10 个城市,我们想按时间报告的名称对其进行排序。 日本大阪。 ...墨西哥墨西哥城。 ... 中国北京。 ... 巴西圣保罗。 ...印度孟买。 ... 上海, 中国。 ... 印度德里。 ... 日本东京。
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);
}
}
【讨论】:
根据用户定义的标准对 ArrayList 进行排序。
模型类
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;
}
}
排序类
class Sortbyroll implements Comparator<Student>
{
public int compare(Student a, Student b)
{
return a.rollno - b.rollno;
}
}
主类
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));
}
}
输出
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc
【讨论】:
为什么不自己做呢?
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
class SortedList<E extends Comparable<E>> extends ArrayList<E> {
@Override
public boolean add(E e) {
int i = Collections.binarySearch(this, e);
if (i < 0) i = ~i;
super.add(i, e);
return true;
} // add(E e)
@Override
public void add(int index, E element) {
this.add(element);
} // add(int, E)
@Override
public boolean addAll(Collection<? extends E> c) {
int oldSize = this.size();
for (E element : c) this.add(element);
return oldSize != this.size();
} // addAll(Collection<? extends E>)
@Override
public boolean addAll(int index, Collection<? extends E> c) {
int oldSize = this.size();
Iterator<? extends E> it = c.iterator();
for (int i = 0; i < index; ++i) it.next();
while (it.hasNext()) this.add(it.next());
return oldSize != this.size();
} // addAll(Collection<? extends E>)
@Override
public E set(int index, E element) {
E ret = this.get(index);
this.remove(index);
this.add(element);
return ret;
} // set(int, E)
} // SortedList<E> Class
public class Solution {
public static void main(String[] args) {
Random r = new Random(1);
List<Integer> sortedList = new SortedList<>();
List<Integer> unsortedList = new ArrayList<>();
for (int i = 0; i < 50; ++i) {
int next = r.nextInt(1000);
sortedList.add(next);
unsortedList.add(next);
} // for (int i = 0; i < 50; ++i)
System.out.println("unsortedList:");
System.out.println(unsortedList);
System.out.println("\nsortedList:");
System.out.println(sortedList);
sortedList.clear();
sortedList.addAll(unsortedList);
System.out.println("\ntest for addAll(Collection) method:");
System.out.println(sortedList);
sortedList.clear();
sortedList.addAll(30, unsortedList);
System.out.println("\ntest for addAll(int, Collection) method:");
System.out.println(sortedList);
sortedList.set(0, 999);
System.out.println("\ntest for set(int, E) method:");
System.out.println(sortedList);
} // main(String[])
} // Solution Class
输出:
unsortedList:
[985, 588, 847, 313, 254, 904, 434, 606, 978, 748, 569, 473, 317, 263, 562, 234, 592, 262, 596, 189, 376, 332, 310, 99, 674, 959, 298, 153, 437, 302, 205, 854, 800, 6, 363, 955, 689, 820, 75, 834, 415, 660, 477, 737, 477, 592, 220, 888, 500, 357]
sortedList:
[6, 75, 99, 153, 189, 205, 220, 234, 254, 262, 263, 298, 302, 310, 313, 317, 332, 357, 363, 376, 415, 434, 437, 473, 477, 477, 500, 562, 569, 588, 592, 592, 596, 606, 660, 674, 689, 737, 748, 800, 820, 834, 847, 854, 888, 904, 955, 959, 978, 985]
test for addAll(Collection) method:
[6, 75, 99, 153, 189, 205, 220, 234, 254, 262, 263, 298, 302, 310, 313, 317, 332, 357, 363, 376, 415, 434, 437, 473, 477, 477, 500, 562, 569, 588, 592, 592, 596, 606, 660, 674, 689, 737, 748, 800, 820, 834, 847, 854, 888, 904, 955, 959, 978, 985]
test for addAll(int, Collection) method:
[6, 75, 205, 220, 357, 363, 415, 477, 477, 500, 592, 660, 689, 737, 800, 820, 834, 854, 888, 955]
test for set(int, E) method:
[75, 205, 220, 357, 363, 415, 477, 477, 500, 592, 660, 689, 737, 800, 820, 834, 854, 888, 955, 999]
【讨论】: