浅谈对象数组或list排序及Collections排序原理_java

常需要对list进行排序,小到List<String>,大到对自定义的类进行排序。不需要自行归并或堆排序。简单实现一个接口即可。

本文先会介绍利用Collections对List<String>进行排序,继而讲到Collections.sort的原理,

再讲到如何对自定义类进行排序,

最后会介绍利用Collections sort对自定义对象进行排序的另外一种方法,将两种排序进行了简单的性能比较。

1、对List<String>排序及Collections.sort的原理

代码如下

List<String> stringList = new ArrayList<String>();
stringList.add("nice");
stringList.add("delicious");
stringList.add("able");
stringList.add("moon");
stringList.add("try");
stringList.add("friend"); 

Collections.sort(stringList); 

for (String str : stringList) {
  System.out.println(str);
} 

其中Collections为java.util.Collections。

查看Collections中的sort实现

@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
  Object[] array = list.toArray();
  Arrays.sort(array);
  int i = 0;
  ListIterator<T> it = list.listIterator();
  while (it.hasNext()) {
    it.next();
    it.set((T) array[i++]);
  }
}

从中可以看出排序主体为Arrays.sort(array);Arrays的sort实现为

public static void sort(Object[] array) {
  // BEGIN android-changed
  ComparableTimSort.sort(array);
  // END android-changed
}

继续追踪,ComparableTimSort的sort实现ComparableTimSort.sort

static void sort(Object[] a)到static void sort(Object[] a, int lo, int hi)到private static void binarySort(Object[] a, int lo, int hi, int start)。在binarySort中用于大小比较部分为

Comparable<Object> pivot = (Comparable) a[start];
int left = lo;
int right = start;
assert left <= right; 

while (left < right) {
  int mid = (left + right) >>> 1;
  if (pivot.compareTo(a[mid]) < 0)
    right = mid;
  else
    left = mid + 1;
} 

会调用Object的compareTo进行比较。而默认类似String和Integer类型都已经覆盖compareTo方法。所以可以自行进行比较

2、对自定义类进行比较

通过上面的介绍了解了Collections排序的原理,下面介绍下自定义对象的排序,先查看下Integer和String的比较原理、然后介绍如何对自定义类进行比较

2.1 我们查看Object的实现发现其中并没有compareTo方法,

再看下Integer定义

public final class Integer extends Number implements Comparable<Integer> 

再看下String的定义

public final class String implements java.io.Serializable, Comparable<String>, CharSequence

我们可以发现他们都继承自Comparable

2.2 查看Comparable接口

可以发现Comparable中只有一个方法

Java代码

public int compareTo(T o);

也就是说实际上binarySort方法中调用的是Comparable的compareTo方法,以此可知只要继承自Comparable,

并实现compareTo即可调用Collections.sort对自定义对象进行排序

2.3 自定义类的比较

下面代码为对User进行排序,首先按姓名字母先后排序,若姓名相同,则按年龄由小到大排序

Java代码

public class MainTest {  

  public static void main(String[] args) {
    List<User> userList = new ArrayList<User>();
    userList.add(new User("Lucy", 19));
    userList.add(new User("Jack", 19));
    userList.add(new User("Jim", 19));
    userList.add(new User("James", 19));
    userList.add(new User("Herry", 19));
    userList.add(new User("Luccy", 19));
    userList.add(new User("James", 18));
    userList.add(new User("Herry", 20));  

    Collections.sort(userList);  

    for (User user : userList) {
      System.out.println(user.getName() + "\t\t" + user.getAge());
    }
  }  

  private static class User implements Comparable<User> {  

    private String name;
    private int  age;  

    public User(String name, int age){
      this.name = name;
      this.age = age;
    }  

    @Override
    public int compareTo(User another) {
      int compareName = this.name.compareTo(another.getName());
      if (compareName == 0) {
        return (this.age == another.getAge() ? 0 : (this.age > another.getAge() ? 1 : -1));
      }
      return compareName;
    }  

    public String getName() {
      return name;
    }  

    public int getAge() {
      return age;
    }
  }
} 

执行后输出为:

Xml代码:

Herry    19
Herry    20
Jack    19
James    18
James    19
Jim   19
Luccy    19
Lucy    19

可以看出只需两点即可

a、继承自Comparable

Java代码

private static class User implements Comparable<User>

b、实现compareTo方法

上面的public int compareTo(User another)为比较的主体

可以看到其中int compareName = this.name.compareTo(another.getName());表示比较姓名

大于返回1,等于返回0,小于会返回-1

若相等则按照int age的大小进行比较。

上面的大于返回1,等于返回0,小于会返回-1也是用来binarySort比较的依据。

3、利用Collections sort的重载函数对自定义对象进行排序

代码如下,仍同2中的一样先比较姓名,若相等再比较年龄输出

Java代码

public class MainTest {  

  public static void main(String[] args) {
    List<User> userList = new ArrayList<User>();
    userList.add(new User("Lucy", 19));
    userList.add(new User("Jack", 19));
    userList.add(new User("Jim", 19));
    userList.add(new User("James", 19));
    userList.add(new User("Herry", 19));
    userList.add(new User("Luccy", 19));
    userList.add(new User("James", 18));
    userList.add(new User("Herry", 20));  

    Collections.sort(userList, new Comparator<User>() {  

      public int compare(User user1, User user2) {
        int compareName = user1.getName().compareTo(user2.getName());
        if (compareName == 0) {
          return (user1.getAge() == user2.getAge() ? 0 : (user1.getAge() > user2.getAge() ? 1 : -1));
        }
        return compareName;
      }
    });  

    for (User user : userList) {
      System.out.println(user.getName() + "\t\t" + user.getAge());
    }
  }  

  private static class User {  

    private String name;
    private int  age;  

    public User(String name, int age){
      this.name = name;
      this.age = age;
    }  

    public String getName() {
      return name;
    }  

    public int getAge() {
      return age;
    }
  }
} 

可以看出其中

Java代码

Collections.sort(userList, new Comparator<User>())

为比较的主体,并且实现了Comparator的compare方法。下面介绍下此种方法的原理

追踪Collections的

Java代码

public static <T> void sort(List<T> list, Comparator<? super T> c)

Java代码

public static <T> void sort(T[] a, Comparator<? super T> c)

Java代码

private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off, Comparator c)

可以发现其中代码如下:

Java代码

if (length < INSERTIONSORT_THRESHOLD) {
  for (int i=low; i<high; i++)
  for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
    swap(dest, j, j-1);
  return;
}

调用Comparator的compare方法

4、以上两种排序性能的比较

binarySort需要进行nlg(n)次的比较最坏情况下n^2次的移动

mergeSort是不断进行二分,二分到很小部分后进行插入排序。所以会比较nlg(n)次移动nlg(n)次。但它需要先复制一份源数据,所以会多占用一倍的空间

所以实际情况可以根据需要选择

以上这篇浅谈对象数组或list排序及Collections排序原理就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, list
对象排序
list数组排序、collections.sort排序、collections排序、collections转list、java collections排序,以便于您获取更多的相关知识。

时间: 2024-09-20 00:31:27

浅谈对象数组或list排序及Collections排序原理_java的相关文章

浅谈php数组array_change_key_case() 函数和array_chunk()函数_php实例

如下所示: <?php /* array_change_key_case() 返回其键均为大写或小写的数组. array array_change_key_case(array input[,int case]) 参数描述:array是要转换键值的数组 case有两个选项:CASE_LOWER,默认选项,以小写字母返回数组的键 CASE_UPPER,以大写字母返回数组的键 */ $input_array = array('a'=>'Java', 'B'=>'Php', 'c'=>'

浅谈Javascript数组(推荐)_javascript技巧

在程序语言中数组的重要性不言而喻,JavaScript中数组也是最常使用的对象之一,数组是值的有序集合,由于弱类型的原因,JavaScript中数组十分灵活.强大,不像是Java等强类型高级语言数组只能存放同一类型或其子类型元素,JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改. 首先,大概说说数组的基本用法. 数组,即Array类型,是开发中最常用的类型之一,javascript中的数组和其他语言最大的区别就是每

浅谈Javascript数组的使用_javascript技巧

上一篇说了数组的索引,这一篇说下数组的使用. 数组的大小 js的数组可以动态调整大小,更确切点说,它没有数组越界的概念,a[a.length]没什么问题.比如声明一个数组a = [1, 3, 5],现在的数组大小是3,最后一个元素的索引是2,但是你依然可以使用a[3],访问a[3]返回的是undefined,给a[3]赋值:a[3] = 7,是给数组a添加了一个元素,现在数组a的长度是4了.你可以试试把下面这段代码放到浏览器里运行下: var a = []; for(int i = 0; i <

浅谈 对象中option 的清空

对象 浅谈<select > 对象中option 的清空 intLength 为 option的个数 :document.all("lstUserId").options.length;lstUserId 为 <select id=lstUserId> 对象: <select id=lstUserId> <option >1</option> <option >3</option> <option

浅谈Java自定义注解和运行时靠反射获取注解_java

java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能. 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annotation 包中. 1.元注解 元注解是指注解的注解.包括  @Retention @Target @Document @Inherited四种. 1.1.@Retention: 定义注解的保留策略 @Retention(RetentionPolicy.SOURCE) //注解仅

浅谈Android开发中项目的文件结构及规范化部署建议_java

一.几句话 使用Gradle及其推荐的项目框架 把密码等敏感数据放入gradle.properties 不要自己写Http客户端,使用Volley或OkHttp库 使用Jackson库来解析JSON数据 避免Guava并出于Dalvik 65K methods limit不要使用过多的库 使用Fragment来绘制UI界面 Activity主要用来管理Fragment 布局文件XML也是代码,好好组织它们 在布局文件里,使用styles以避免重复的属性 使用多个style文件而不是一个巨大的st

浅谈java+内存分配及变量存储位置的区别_java

Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中(new 出来的对象) ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量 ◆非RAM存储:硬盘等永久

浅谈java中BigDecimal的equals与compareTo的区别_java

这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都是以sun jdk 1.4.2版本为例,其他版本实现未必一致,请忽略] 首先看一下BigDecimal的equals方法: public boolean equals(Object x){ if (!(x instanceof BigDecimal)) return false; BigDecima

浅谈Java多线程编程中Boolean常量的同步问题_java

在JAVA中通过synchronized语句可以实现多线程并发.使用同步代码块,JVM保证同一时间只有一个线程可以拥有某一对象的锁.锁机制实现了多个线程安全地对临界资源进行访问.   同步代码写法如下:   代码1: Object obj = new Object(); ... synchronized(obj) { //TODO: 访问临界资源 } JAVA的多线程总是充满陷阱,如果我们用Boolean作为被同步的对象,可能会出现以下两种情况:   一. 以为对一个对象加锁,实际同步的是不同对