上接,《java学习脚印:集合(Collection)之实现类》。
集合框架提供了一些诸如排序,查找,打散顺序(Shuffling),逆置,旋转,取最大值,取最小值等基本算法,还可以使用集合框架中的接口实现自己的算法。
这里重点提示一下排序算法和查找算法,其他的算法可参考相关API。
java中的sort排序采用稳定的归并排序算法。
要对一个集合进行排序有两种方法:
1) 实现Comparable接口,进行自然排序。
Comparable该接口声明有方法:
int compareTo(T o),利用该方法对元素进行排序,这称为自然排序(natural ordering) 。对于没有实现Comparable接口的类调用Collections.sort()或者Arrays.sort()方法均会抛出ClassCastException异常。
下表给出了实现了Comparable接口的一些类及其自然排序。
(来自:http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html)。
Class |
NaturalOrdering |
|
Signednumerical(有符号数值比较) |
|
Unsignednumerical(无符号数值比较) |
|
Signednumerical |
|
Signednumerical |
|
Signednumerical |
|
Signednumerical |
|
Signednumerical |
|
Signednumerical |
|
Signednumerical |
|
|
|
System-dependentlexicographic on path name (依赖于平台的路径字典序) |
|
Lexicographic(字典序) |
|
Chronological(年代) |
|
Locale-specificlexicographic |
2)构造Comparators比较器,自定义排序规则。
Comparators接口声明有一个比较方法:
public interface Comparator<T> {
int compare(T o1, T o2);
}
通过像集合类或者sort方法传递一个Comparator即可实现自己所需要的排序。
具体可参见代码案例部分。
这里举出一个首先利用自然排序即按Date排序,然后按照Comparator排序的案例。
注意两种排序方式的使用,以及观察稳定排序的特点。
代码清单1-1 :CollectionsDemo8.java
package com.learningjava; import java.text.SimpleDateFormat; import java.util.*; /** * This program illustrate usage of sort method in Collections * @author wangdq * 2013-11-4 */ public class CollectionsDemo8 { public static void main(String[] args) { Employee[] staffs = new Employee[]{ new Employee("Steve",5500,1986,7,13), new Employee("Jack",7000,1986,7,5), new Employee("Karl",5000,1985,11,2), new Employee("Jason",7000,1980,8,12), }; //before sort System.out.println("Original: "+Arrays.toString(staffs)); //create a backup arraylist and shuffled it ArrayList<Employee> bkList1 = new ArrayList<Employee>(Arrays.asList(staffs)); Collections.shuffle(bkList1); System.out.println("Shuffled: "+bkList1); //sorted it by natural ordering(compare date) ArrayList<Employee> bkList2 = new ArrayList<Employee>(Arrays.asList(staffs)); Collections.sort(bkList2); System.out.println("date order: "+bkList2); //sorted it by name via providing a Comparator ArrayList<Employee> bkList3 = new ArrayList<Employee>(Arrays.asList(staffs)); Collections.sort(bkList3,new Comparator<Employee>(){ @Override public int compare(Employee e1, Employee e2) { // TODO Auto-generated method stub return e1.getName().compareTo(e2.getName()); } }); System.out.println("name order: "+bkList3); //sort based on bkList3 //thus we get sorted by name and then by salary //check if it is a stable sort Collections.sort(bkList3,new Comparator<Employee>(){ @Override public int compare(Employee e1, Employee e2) { return Double.valueOf(e1.getSalary()). compareTo(Double.valueOf(e2.getSalary())); } }); System.out.println("salary order: "+bkList3); } } /** * a class to descript employee * origin by the book 《Core Java,Volume I:Fundamentals》 * @version 1.1 2013-08-07 */ class Employee implements Comparable<Employee>{ /** * * @param name name to set * @param salary salary to set * @param year month day to create a GregorianCalendar */ public Employee(String name, double salary, int year,int month,int day) { this.name = name; this.salary = salary; GregorianCalendar calendar = new GregorianCalendar(year,month-1,day); this.hireDay = calendar.getTime(); setId(); } public void raiseSalary(double percent) { double raise = salary*percent/100; salary += raise; } public String getName() { return name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Date getHireday() { return (Date)hireDay.clone(); } public void setHireday(Date hireDay) { this.hireDay = hireDay; } public int getId() { return id; } private void setId() { this.id = nextId; nextId++; } @Override //sort by hireDay public int compareTo(Employee o) { // TODO Auto-generated method stub return this.hireDay.compareTo(o.getHireday()); } @Override public String toString() { SimpleDateFormat dateformat =new SimpleDateFormat("yyyy-MM-dd"); String date = dateformat.format(hireDay); return "["+name+","+getSalary()+","+date+"]"; } private String name; private double salary; private Date hireDay; private int id; private static int nextId = 1; }
运行输出
Original: [[Steve,5500.0,1986-07-13], [Jack,7000.0,1986-07-05], [Karl,5000.0,1985-11-02], [Jason,7000.0,1980-08-12]]
Shuffled: [[Jason,7000.0,1980-08-12], [Steve,5500.0,1986-07-13], [Karl,5000.0,1985-11-02], [Jack,7000.0,1986-07-05]]
date order: [[Jason,7000.0,1980-08-12], [Karl,5000.0,1985-11-02], [Jack,7000.0,1986-07-05], [Steve,5500.0,1986-07-13]]
name order: [[Jack,7000.0,1986-07-05], [Jason,7000.0,1980-08-12], [Karl,5000.0,1985-11-02], [Steve,5500.0,1986-07-13]]
salary order: [[Karl,5000.0,1985-11-02], [Steve,5500.0,1986-07-13], [Jack,7000.0,1986-07-05], [Jason,7000.0,1980-08-12]]
这里先按姓名进行了排序,然后按工资进行了排序,工资排序中jack和jason工资相等,因为是稳定排序,所以最后的结果是工资想等者按先前的姓名排序结果排列。
java查找排序采用二分查找,要求必须是有序的顺序存贮的列表,否则影响查找结果和查找效率。
查找成功时,返回该元素在列表中的索引;当查找失败时,返回的索引并非无用,它恰好给出了插入该元素的一个参考,查找失败时,元素插入位置为:-pos-1,如下:
int pos = Collections.binarySearch(list, key);
if (pos < 0)
l.add(-pos-1, key);
下面给出一个实例代码,以加深理解。
代码清单1-2 :CollectionsDemo9.java
package com.learningjava; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; /** * This program illustrate usage of search method in Collections * @author wangdq * 2013-11-4 */ public class CollectionsDemo9 { public static void main(String[] args) { Integer[] ints = new Integer[]{5,13,19,21,37,56,64,75,80,88,92}; ArrayList<Integer> bkList1 = new ArrayList<>(Arrays.asList(ints)); //before reverse System.out.println("original list: "+Arrays.toString(ints)); //reverse list Collections.reverse(bkList1); System.out.println("reversed list: "+bkList1); //sort the list ArrayList<Integer> bkList2 = new ArrayList<>(Arrays.asList(ints)); Collections.sort(bkList2); System.out.println("sorted list: "+bkList2); //binary search with included key int index = Collections.binarySearch(bkList2, Integer.valueOf(21)); System.out.println("search 21: "+index); //binary search with non-included key int Index2 = Collections.binarySearch(bkList2, Integer.valueOf(85)); System.out.println("search 85: "+Index2); if (Index2 < 0) bkList2.add(-Index2-1, Integer.valueOf(85));//insertposition -Index2-1 System.out.println("after insert: "+bkList2); } }
original list: [5, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92]
reversed list: [92, 88, 80, 75, 64, 56, 37, 21, 19, 13, 5]
sorted list: [5, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92]
search 21: 3
search 85: -10
after insert: [5, 13, 19, 21, 37, 56, 64, 75, 80, 85, 88, 92]