Java集合框架实现自定义排序

简介:

Java集合框架针对不同的数据结构提供了多种排序的方法,
虽然很多时候我们可以自己实现排序,比如数组等,但是灵活的使用JDK提供的排序方法,可以提高开发效率,而且通常JDK的实现要比自己造的轮子性能更优化。

1.使用Arrays对数组进行排序

Java API对Arrays类的说明是:此类包含用来操作数组(比如排序和搜索)的各种方法。

(1)使用Arrays排序

Arrays使用非常简单,直接调用sort()即可:

1
2
3
4
5
6
7
8
9
10
11
int [] arr =  new  int [] { 5 , 8 ,- 2 , 0 , 10 };
         Arrays.sort(arr);
         for ( int  i= 0 ;i<arr.length;i++){
             System.out.print(arr[i]+ "," );
         }
                 
         char [] charArr =  new  char [] { 'b' , 'a' , 'c' , 'd' , 'D' };
         Arrays.sort(charArr);
         for ( int  i= 0 ;i<arr.length;i++){
             System.out.print(charArr[i]+ "," );
         }

如果需要降序排序, 升序排序后逆序即可:

1
Collections.reverse(Arrays.asList(arr)); 

(2)Arrays.sort()的实现

查看源码会发现,Arrays.sort()有许多重载的方法,如sort(int[] a)、sort(long[] a) 、sort(char[] a)等,

1
2
3
public  static  void  sort( int [] a) {
        DualPivotQuicksort.sort(a);
    }

但最终都是调用了DualPivotQuicksort.sort(a)的方法,

这是一个改进的快速排序,采用多路快速排序法,比单路快速排序法有更好的性能,
并且根据数组长度不同会最终选择不同的排序实现,

看一下这个方法的实现,这里不作展开:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  static  void  sort( char [] a) {
         sort(a,  0 , a.length -  1 );
     }
     
  public  static  void  sort( char [] a,  int  left,  int  right) {
         // Use counting sort on large arrays
         if  (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
             int [] count =  new  int [NUM_CHAR_VALUES];
 
             for  ( int  i = left -  1 ; ++i <= right;
                 count[a[i]]++
             );
             for  ( int  i = NUM_CHAR_VALUES, k = right +  1 ; k > left; ) {
                 while  (count[--i] ==  0 );
                 char  value = ( char ) i;
                 int  s = count[i];
 
                 do  {
                     a[--k] = value;
                 while  (--s >  0 );
             }
         else  // Use Dual-Pivot Quicksort on small arrays
             doSort(a, left, right);
         }
     }

  

1
2
3
4
5
6
private  static  void  doSort( char [] a,  int  left,  int  right) {
         // Use Quicksort on small arrays
         if  (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right,  true );
             return ;
         }  


2.使用Comparator或Comparable进行自定义排序

集合框架中,Collections工具类支持两种排序方法:

Collections.sort(List<T> list);
Collections.sort(List<T> list, Comparator<? super T> c)

如果待排序的列表中是数字或者字符,可以直接使用Collections.sort(list);

当需要排序的集合或数组不是单纯的数字型时,需要自己定义排序规则,实现一个Comparator比较器。

下面了解一下Comparable和Comparator的应用。

Comparable 是排序接口,一个类实现了Comparable接口,就意味着该类支持排序。 

Comparable 的定义如下:

1
2
3
public  interface  Comparable<T> {
     public  int  compareTo(T o);
}

接口中通过x.compareTo(y) 来比较x和y的大小。若返回负数,意味着x比y小;返回零,意味着x等于y;返回正数,意味着x大于y

当然这里的大于等于小于的意义是要根据我们的排序规则来理解的

Comparator是比较器接口,如果需要控制某个类的次序,而该类本身没有实现Comparable接口,也就是不支持排序,那么可以建立一个类需要实现Comparator接口即可,在这个接口里制定具体的排序规则,
Comparator接口的定义如下:

1
2
3
4
public  interface  Comparator<T> {
     int  compare(T o1, T o2);
     boolean  equals(Object obj);
} 

一个比较器类要实现Comparator接口一定要实现compareTo(T o1, T o2) 函数,如果没有必要,可以不去重写equals() 函数。
因为在Object类中已经实现了equals(Object obj)函数方法。

int compare(T o1, T o2)  和上面的x.compareTo(y)类似,定义排序规则后返回正数,零和负数分别代表大于,等于和小于。

 

3.如何对HashMap的key或者value排序

HashMap作为kay-value结构,本身是无序的,排序比较灵活,一般会通过一个list进行保存。

下面的代码针对HashMap的key和value排序,提供几种实现的思路:

(1)转换为key数组,按照key排序

1
2
3
4
5
Object[] key_arr = hashmap.keySet().toArray();    
Arrays.sort(key_arr);    
for   (Object key : key_arr) {    
     Object value = hashmap.get(key);    
}  

(2)对HashMap的value进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
  * 针对HashMap的value进行排序
  * @author Bingyue
  */
public  class  HashMapSort {
 
     public  static  void  main(String[] args) {
         HashMap<String, Integer> map =  new  HashMap<String, Integer>(){{
             put( "tom" 18 );
             put( "jack" 25 );
             put( "susan" 20 );
             put( "rose" 38 );
         }};
          
         ValueComparator cmptor =  new  ValueComparator(map); 
         /**
          * 转换为有序的TreeMap进行输出
          */
         TreeMap<String, Integer> sorted_map =  new  TreeMap<String, Integer>(cmptor);
         sorted_map.putAll(map);
          
         for (String sortedkey : sorted_map.keySet()){
             System.out.println(sortedkey+map.get(sortedkey));
         }
         /**
          * 转换为有序的list进行排序
          */
         List<String> keys =  new  ArrayList<String>(map.keySet());
         Collections.sort(keys, cmptor);
         for (String key : keys) {
              System.out.println(key+map.get(key));
         }
     }
     static  class  ValueComparator  implements  Comparator<String> {
         HashMap<String, Integer> base_map;
         public  ValueComparator(HashMap<String, Integer> base_map) {
             this .base_map = base_map;
         }
         public  int  compare(String arg0, String arg1) {
             if  (!base_map.containsKey(arg0) || !base_map.containsKey(arg1)) {
                 return  0 ;
             }
             //按照value从小到大排序
             if  (base_map.get(arg0) < base_map.get(arg1)) {
                 return  - 1 ;
             else  if  (base_map.get(arg0) == base_map.get(arg1)) {
                 return  0 ;
             else  {
                 return  1 ;
             }
         }
     }
}

输出:

tom18     
susan20   
jack25    
rose38   
tom18   
susan20  
jack25    
rose38    

4.通过Comparator自定义实体排序

如果你的List包装的是基本类型或者String,只要Collections.sort(list)即可,
但是如果list中保存的是实体bean等,就需要自己定义排序规则。

Java可以对ArrayList中的对象按照该对象某属性排序,下面的操作实现对Person实体列表的排序:

(1)定义Person实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  class  Person{
      String name;
      int  age;
  public  Person(String name, int  age){
      this .name = name;
      this .age = age; 
  }
 
  public  int  getAge() {
      return  age;
  }
  public  void  setAge( int  age) {
      this .age = age;
  }
  public  String getName() {
      return  name;
  }
  public  void  setName(String name) {
      this .name = name;
  }
} 

(2)实现Comparator接口,编写排序规则

1
2
3
4
5
6
7
8
9
10
public  class  Mycomparator  implements  Comparator{<br> // 实现Comparator接口,也就是定义排序规则
     public  int  compare(Object o1,Object o2) {
         Person p1=(Person)o1;
         Person p2=(Person)o2;
        if (p1.age<p2.age)
            return  1 ;
        else
            return  0 ;
        }
} 


(3)测试排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  class  ListSort {
      public  static  void  main(String[] args){
          ArrayList list =  new  ArrayList();
          list.add( new  Person( "lcl" , 28 ));
          list.add( new  Person( "fx" , 23 ));
          list.add( new  Person( "wqx" , 29 ));
          Comparator comp =  new  Mycomparator();
          Collections.sort(list,comp);
          for ( int  i =  0 ;i<list.size();i++){
              Person p = (Person)list.get(i);
              System.out.println(p.getName());
          }
    
      }
  
}

  


目录
相关文章
剑指 Offer 45. 把数组排成最小的数 Java自定义排序
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
|
Java
Java - Map 自定义排序 Lambda 之 Comparator
Java - Map 自定义排序 Lambda 之 Comparator
1373 0
|
10天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
12天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
12天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
12天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
35 3
|
12天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
93 2
|
21天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
46 6
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####