杰瑞科技汇

Java中array.sort()如何自定义排序规则?

Of course! Let's dive deep into the Arrays.sort() method in Java. This is a fundamental and frequently used method for sorting arrays.

Java中array.sort()如何自定义排序规则?-图1
(图片来源网络,侵删)

Overview

Arrays.sort() is a utility method from the java.util.Arrays class used to sort elements in an array. It's highly optimized and versatile, handling different data types and offering different sorting algorithms based on the input.

There are two main categories of Arrays.sort():

  1. Sorting Primitive Arrays (e.g., int[], double[])
  2. Sorting Object Arrays (e.g., String[], Integer[], custom objects)

Sorting Primitive Arrays

When you sort an array of primitives, the elements are sorted in their natural ascending order.

Syntax

import java.util.Arrays;
// For all primitive types: byte, short, int, long, float, double, char
Arrays.sort(primitiveArray);

Example: Sorting an int[] array

The sorting is done in-place, meaning the original array is modified.

import java.util.Arrays;
public class PrimitiveSortExample {
    public static void main(String[] args) {
        int[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6};
        System.out.println("Array before sorting: " + Arrays.toString(numbers));
        // Sort the array in ascending order
        Arrays.sort(numbers);
        System.out.println("Array after sorting:  " + Arrays.toString(numbers));
    }
}

Output:

Array before sorting: [5, 1, 9, 3, 7, 2, 8, 4, 6]
Array after sorting:  [1, 2, 3, 4, 5, 6, 7, 8, 9]

How it Works (Algorithm)

For primitive arrays, Java uses a highly optimized, dual-pivot Quicksort implementation. This algorithm is very fast on average and has a time complexity of O(n log n).


Sorting Object Arrays

When you sort an array of objects, you need to provide a way for the sort method to compare the objects. This is done using a Comparator.

A. Natural Ordering (Using Comparable)

If the objects in your array belong to a class that implements the java.lang.Comparable interface, they have a "natural ordering" and can be sorted without any extra arguments.

The Comparable interface defines a single method: int compareTo(T o).

  • Returns a negative integer if the current object is less than the specified object.
  • Returns zero if they are equal.
  • Returns a positive integer if the current object is greater than the specified object.

Example: Sorting an Integer[] array The Integer class already implements Comparable.

import java.util.Arrays;
public class NaturalOrderSortExample {
    public static void main(String[] args) {
        Integer[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6};
        System.out.println("Array before sorting: " + Arrays.toString(numbers));
        // Sorts based on the natural ordering of Integer objects
        Arrays.sort(numbers);
        System.out.println("Array after sorting:  " + Arrays.toString(numbers));
    }
}

Output:

Array before sorting: [5, 1, 9, 3, 7, 2, 8, 4, 6]
Array after sorting:  [1, 2, 3, 4, 5, 6, 7, 8, 9]

Example: Sorting a String[] array String also implements Comparable, where the natural order is lexicographical (alphabetical).

import java.util.Arrays;
public class StringSortExample {
    public static void main(String[] args) {
        String[] fruits = {"Banana", "Apple", "Orange", "Grape", "Mango"};
        System.out.println("Array before sorting: " + Arrays.toString(fruits));
        Arrays.sort(fruits);
        System.out.println("Array after sorting:  " + Arrays.toString(fruits));
    }
}

Output:

Array before sorting: [Banana, Apple, Orange, Grape, Mango]
Array after sorting:  [Apple, Banana, Grape, Mango, Orange]

B. Custom Ordering (Using Comparator)

If you want to sort objects in a way that's different from their natural order, or if the class doesn't implement Comparable, you must provide a Comparator.

A Comparator is a separate object that defines a custom comparison logic. You can define it using a Comparator interface or, more commonly, a lambda expression.

Syntax:

Arrays.sort(objectArray, comparator);

Example: Sorting a custom Person array by age

Let's say we have a Person class that only implements Comparable by name. We want to sort a list of people by their age.

import java.util.Arrays;
import java.util.Comparator;
// Person class with a natural ordering by name
class Person implements Comparable<Person> {
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}
public class CustomSortExample {
    public static void main(String[] args) {
        Person[] people = {
            new Person("Alice", 30),
            new Person("Charlie", 25),
            new Person("Bob", 35)
        };
        System.out.println("Array before sorting: " + Arrays.toString(people));
        // Sort by natural order (name)
        Arrays.sort(people);
        System.out.println("Sorted by name:      " + Arrays.toString(people));
        // Sort by age using a lambda expression as a Comparator
        // (p1, p2) -> p1.age - p2.age  is a concise way to write a comparator
        Arrays.sort(people, (p1, p2) -> Integer.compare(p1.age, p2.age));
        System.out.println("Sorted by age:      " + Arrays.toString(people));
    }
}

Output:

Array before sorting: [Alice (30), Charlie (25), Bob (35)]
Sorted by name:      [Alice (30), Bob (35), Charlie (25)]
Sorted by age:      [Charlie (25), Alice (30), Bob (35)]

How it Works (Algorithm)

For object arrays, the default implementation uses a Timsort. Timsort is a hybrid sorting algorithm derived from Merge Sort and Insertion Sort. It's also very efficient with a time complexity of O(n log n) in the worst case and performs exceptionally well on partially sorted arrays.


Key Overloads and Variations

The Arrays.sort() method has several useful overloads:

Sorting a Range of an Array

You can sort only a specific portion of an array, from a fromIndex (inclusive) to a toIndex (exclusive).

import java.util.Arrays;
public class RangeSortExample {
    public static void main(String[] args) {
        int[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6};
        System.out.println("Original array: " + Arrays.toString(numbers));
        // Sort only the subarray from index 2 to 6 (elements 9, 3, 7, 2)
        Arrays.sort(numbers, 2, 6);
        System.out.println("After sorting range [2, 6): " + Arrays.toString(numbers));
    }
}

Output:

Original array: [5, 1, 9, 3, 7, 2, 8, 4, 6]
After sorting range [2, 6): [5, 1, 2, 3, 7, 9, 8, 4, 6]

(Note: The range is [fromIndex, toIndex), meaning toIndex is exclusive.)

Parallel Sorting

For very large arrays, you can leverage multi-core processors to sort the array in parallel. This can significantly improve performance.

import java.util.Arrays;
public class ParallelSortExample {
    public static void main(String[] args) {
        // Create a large array
        int[] largeArray = new int[10_000_000];
        for (int i = 0; i < largeArray.length; i++) {
            largeArray[i] = (int) (Math.random() * largeArray.length);
        }
        // System.out.println("Array is too large to print, but we can sort it.");
        // Sort using the parallel sort algorithm
        long startTime = System.currentTimeMillis();
        Arrays.parallelSort(largeArray);
        long endTime = System.currentTimeMillis();
        System.out.println("Parallel sort took: " + (endTime - startTime) + " ms");
    }
}

How it Works: Arrays.parallelSort() uses a fork-join pool to divide the array into smaller chunks, sorts them in parallel, and then merges the results. It's based on a modified Merge Sort algorithm.


Summary Table

Method Signature What it Does Algorithm Used Time Complexity
Arrays.sort(primitiveArray) Sorts a primitive array in natural ascending order. Dual-Pivot Quicksort O(n log n)
Arrays.sort(objectArray) Sorts an object array using its natural ordering (Comparable). Timsort O(n log n)
Arrays.sort(objectArray, comparator) Sorts an object array using a custom Comparator. Timsort O(n log n)
Arrays.sort(array, fromIndex, toIndex) Sorts a specific range of an array. Same as above O(k log k) where k is the range size
Arrays.parallelSort(array) Sorts an array using multiple threads for better performance on large arrays. Parallel Merge Sort O(n log n)

Important Considerations

  • In-Place Sort: Arrays.sort() modifies the original array. It does not return a new sorted array.
  • Stability: Timsort (used for objects) is a stable sort. This means that if two elements are equal according to the comparator, their relative order in the original array will be preserved. The dual-pivot Quicksort (used for primitives) is not stable.
  • Null Elements: Attempting to sort an array that contains null elements (unless you are using a Comparator that can handle nulls) will result in a NullPointerException.
分享:
扫描分享到社交APP
上一篇
下一篇