【问题标题】:Sorted collection in JavaJava中的排序集合
【发布时间】:2010-09-29 19:09:24
【问题描述】:

我是 Java 初学者。请建议可以/应该使用哪些集合来维护 Java 中的排序列表。我试过MapSet,但它们不是我想要的。

【问题讨论】:

    标签: java sorting collections


    【解决方案1】:

    这来得太晚了,但是 JDK 中有一个类只是为了有一个排序列表。它被命名为“java.util.PriorityQueue”(与其他Sorted* 接口有点乱)。它可以对Comparable<?>s 或使用Comparator 进行排序。

    与使用Collections.sort(...) 排序的List 的区别在于,这将始终保持偏序,具有O(log(n)) 插入性能,通过使用堆数据结构,而插入排序ArrayList 将是 O(n)(即,使用二分查找和移动)。

    但是,与List 不同,PriorityQueue 不支持索引访问 (get(5)),访问堆中项目的唯一方法是一次取出一个(因此名称为PriorityQueue)。

    【讨论】:

    • imo 这个答案值得更多的支持,因为它指出了唯一在 JDK 中具有该功能的 Collection
    • 来自 Javadoc:“方法 iterator() 中提供的迭代器不能保证以任何特定顺序遍历 PriorityQueue 的元素。”
    • @giraff:优先级队列就是这样,一种在保持优先级队列方面非常有效的数据结构。您可以从前面轮询并按排序顺序获取数据项。然而,堆内部并不维护元素的总顺序(这就是它们如此高效的原因),因此如果不执行轮询操作,就无法按顺序访问元素。
    • @chrispy 这在一定程度上取决于您究竟想用您的数据结构实现什么。堆是维护项目列表并稍后以有序方式检索它们的有效方法 - 使用迭代器不起作用,但如果您从中轮询,您将按顺序获取数据。检索具有破坏性,但在许多情况下仍然可以。所以我觉得这个答案很好。
    • @MartinProbst 请更正您的回答,明确指出该集合不能按预期顺序迭代。正如许多人所说,这非常具有误导性!
    【解决方案2】:

    TreeMap 和 TreeSet 将按排序顺序为您提供对内容的迭代。或者您可以使用 ArrayList 并使用 Collections.sort() 对其进行排序。所有这些类都在 java.util 中

    【讨论】:

    • 这有两个主要缺点,第一个是 Set 不能有重复项。第二个是,如果您使用列表和 Collections.sort(),您往往会不断地对巨大的列表进行排序并且性能很差。当然可以使用“脏”标志,但并不完全相同。
    • 这带来了一个问题,我们是否在 Java 中有一个选项允许重复并提供类似于 Set(平衡二叉树)的性能
    • SortedSet/TreeMap 的另一个问题是,即使您的键是唯一的但您的不同键的比较器值相同,它们也无法工作。 A TreeSet((UniqueKey1, UniqueKey2) -> Comparator.compare(otherValueLookup.get(key1), otherValueLookup.get(key2)) 这将失败排序,因为如果 otherValue 相同,它将不会添加值!结论:TreeSet/TreeMap 获胜'如果两个键不同但根据比较器相等,则不添加值
    • 需要补充一点,我们仍然可以使用TreeSet/TreeMap,解决方法是在key相同的情况下创建一个Randomizer:ThreadLocalRandom r = ThreadLocalRandom.current(); boolean randomBoolean = r.nextBoolean(); if (key1.equals(key2)) { // ** 如果它们相等,随机比较器 ** 返回 randomBoolean 吗? 1:-1; } else { 返回 key1.compareTo(key2); }
    【解决方案3】:

    如果您想维护一个排序列表,您将经常修改(即,除了排序之外,还允许重复并且其元素可以有效地由索引引用),然后使用 ArrayList 但当您需要插入元素时,请始终使用 Collections.binarySearch() 来确定添加给定元素的索引。后一种方法告诉您需要插入的索引,以使您的列表保持排序。

    【讨论】:

    • n 次插入将是 O(n^2)。 TreeSet 将为您提供更简洁的代码和 O(n log n)。 OTOH,对于 infrequent 修改,数组的二进制搜索将更快并且使用更少的内存(因此更少的 GC 开销)。
    • 为了保持代码干净并且仍然允许重复,创建一个按排序顺序插入值的 SortedList 类很容易。
    • 如果您能接受@TomHawtin-tackline 提到的警告,这比最受好评的答案 imo 更好的答案。对于大多数情况而言,迭代器按预期工作至关重要。
    • 顺便提一下,Tom 在特定行为上是正确的:树集将为您提供更有效的修改。但是树集不是列表(严格意义上来说,有索引引用的元素并允许重复)并且发布者说他们想要一个列表。
    • 谢谢你,尼尔,太棒了!
    【解决方案4】:

    使用 Google Guava 的 TreeMultiset 类。 Guava 有一个壮观的集合 API。

    提供维护排序顺序的 List 实现的一个问题是在 add() 方法的 JavaDocs 中做出的承诺。

    【讨论】:

    • 感谢多集建议
    • +1 用于提及List 始终添加在末尾的要求。
    • 请注意,TreeMultiSet 仍然不允许重复元素(compareTo() 返回 0,而不是 equals() 检查的元素)。如果您倾向于添加多个相同优先级的项目,它只会增加第一个添加的项目的计数,丢弃其他项目并有效地成为一个很好的计数袋实现。
    【解决方案5】:

    您想要SortedSet 实现,即TreeSet

    【讨论】:

    • 不一定;集合不能有重复的值。这取决于 OP 的要求。
    【解决方案6】:

    有几个选项。如果您不想重复并且您插入的对象具有可比性,我建议使用 TreeSet。

    您也可以使用 Collections 类的静态方法来执行此操作。

    请参阅Collections#sort(java.util.List)TreeSet 了解更多信息。

    【讨论】:

      【解决方案7】:

      如果您只想对列表进行排序,请使用任何类型的 List 并使用 Collections.sort()。如果您想确保列表中的元素是唯一的并且始终排序,请使用SortedSet

      【讨论】:

        【解决方案8】:

        我所做的是实现 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来实现,效率更高。
        【解决方案9】:

        实现您想要的排序列表的最有效方法是实现一个可索引的跳过列表,如下所示:Wikipedia: Indexable skiplist。 它将允许在 O(log(n)) 中进行插入/删除,并允许同时进行索引访问。它还允许重复。

        Skiplist 是一种非常有趣的数据结构,我会说它被低估了。 不幸的是,Java 基础库中没有索引的跳过列表实现,但您可以使用开源实现之一或自己实现它。有常规的 Skiplist 实现,例如 ConcurrentSkipListSetConcurrentSkipListMap

        【讨论】:

          【解决方案10】:

          TreeSet 不起作用,因为它们不允许重复,而且它们不提供在特定位置获取元素的方法。 PriorityQueue 不起作用,因为它不允许在特定位置获取元素,这是列表的基本要求。 我认为您需要实现自己的算法来维护具有 O(logn) 插入时间的 Java 中的排序列表,除非您不需要重复项。 也许解决方案可能是使用 TreeMap ,其中键是覆盖 equals 方法的项目的子类,以便允许重复。

          【讨论】:

            【解决方案11】:

            使用 LambdaJ

            如果您使用的是 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倍),但是你能找到更可读的代码吗?

            使用 lambda 表达式与 java 8 进行排序

            Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
            //or
            persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
            

            【讨论】:

            • 在您使用 java 8 lambda 表达式的最后一个示例中,如何反向排序?
            • @RajatShah 我想你可以这样做-(p1.getAge().compareTo(p2.getAge()))
            • @RajatShah 很高兴为您提供帮助
            【解决方案12】:

            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() 时按顺序获取值,并且也有重复。

            【讨论】:

              【解决方案13】:

              对于 Set,您可以使用 TreeSet。 TreeSet 根据自然排序或传递给该特定对象的 Comparable 的任何排序顺序对其元素进行排序。 对于地图,请使用 TreeMap。 TreeMap 提供对键的排序。要将对象作为键添加到 TreeMap,该类应实现可比较接口,该接口又强制实现包含排序顺序定义的 compare to() 方法。 http://techmastertutorial.in/java-collection-impl.html

              【讨论】:

                【解决方案14】:

                你想要的是一个二叉搜索树。它保持排序顺序,同时为搜索、删除和插入提供对数访问(除非你有一个退化的树 - 然后它是线性的)。它很容易实现,你甚至可以让它实现 List 接口,但是索引访问变得复杂了。

                第二种方法是先使用 ArrayList,然后再使用冒泡排序实现。因为您一次插入或删除一个元素,所以插入和删除的访问时间是线性的。搜索是对数和索引访问常量(对于 LinkedList,时间可能会有所不同)。您需要的唯一代码是 5 行,可能是 6 行冒泡排序。

                【讨论】:

                  【解决方案15】:

                  你可以使用 Arraylist 和 Treemap,正如你所说的你想要重复的值,然后你不能使用 TreeSet,虽然它也是排序的,但是你必须定义比较器。

                  【讨论】:

                    【解决方案16】:

                    使用 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

                    【讨论】:

                      【解决方案17】:

                      使用TreeSet 以排序顺序给出元素。或使用Collection.sort()Comparator() 进行外部排序。

                      【讨论】:

                      【解决方案18】:
                      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);    
                      }
                      

                      【讨论】:

                        【解决方案19】:

                        使用 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);
                        
                            }
                        
                        }
                        

                        【讨论】:

                          【解决方案20】:

                          根据用户定义的标准对 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
                          

                          【讨论】:

                            【解决方案21】:

                            为什么不自己做呢?

                            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]
                            

                            【讨论】:

                              猜你喜欢
                              • 2018-01-02
                              • 1970-01-01
                              • 2012-06-30
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多