java学习脚印:集合(Collection)之算法

来源:互联网 发布:陈一发知乎 编辑:程序博客网 时间:2024/06/05 20:42

java学习脚印:集合(Collection)之算法

上接,《java学习脚印:集合(Collection)之实现类》。


集合框架提供了一些诸如排序,查找,打散顺序(Shuffling),逆置,旋转,取最大值,取最小值等基本算法,还可以使用集合框架中的接口实现自己的算法。

这里重点提示一下排序算法和查找算法,其他的算法可参考相关API。


1.排序算法

1.1 java中对象排序的方式

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

Byte

Signednumerical(有符号数值比较)

Character

Unsignednumerical(无符号数值比较)

Long

Signednumerical

Integer

Signednumerical

Short

Signednumerical

Double

Signednumerical

Float

Signednumerical

BigInteger

Signednumerical

BigDecimal

Signednumerical

Boolean

Boolean.FALSE< Boolean.TRUE

File

System-dependentlexicographic on path name

(依赖于平台的路径字典序)

String

Lexicographic(字典序)

Date

Chronological(年代)

CollationKey

Locale-specificlexicographic


2)构造Comparators比较器,自定义排序规则。

Comparators接口声明有一个比较方法:

public interface Comparator<T> {
    int compare(T o1, T o2);
}

通过像集合类或者sort方法传递一个Comparator即可实现自己所需要的排序。

具体可参见代码案例部分。

1.2 代码实例

这里举出一个首先利用自然排序即按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 sortSystem.out.println("Original:"+Arrays.toString(staffs));//create a backup arraylist and  shuffled itArrayList<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 ComparatorArrayList<Employee> bkList3 = new ArrayList<Employee>(Arrays.asList(staffs));Collections.sort(bkList3,new Comparator<Employee>(){@Overridepublic int compare(Employee e1, Employee e2) {// TODO Auto-generated method stubreturn 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 sortCollections.sort(bkList3,new Comparator<Employee>(){@Overridepublic 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 hireDaypublic int compareTo(Employee o) {// TODO Auto-generated method stubreturn this.hireDay.compareTo(o.getHireday());}@Overridepublic 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工资相等,因为是稳定排序,所以最后的结果是工资想等者按先前的姓名排序结果排列。


2.查找算法

    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 reverseSystem.out.println("original list:"+Arrays.toString(ints));//reverse listCollections.reverse(bkList1);System.out.println("reversed list:"+bkList1);//sort the listArrayList<Integer> bkList2 = new ArrayList<>(Arrays.asList(ints));Collections.sort(bkList2);System.out.println("sorted list:"+bkList2);//binary search with included keyint index = Collections.binarySearch(bkList2, Integer.valueOf(21));System.out.println("search 21:"+index);//binary search with non-included keyint 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-1System.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]