目录Java数组排序排序的基本概念与重要性经典排序算法:冒泡排序冒泡排序的实现原理代码实现:升序排列交换变量的注意事项Java标准库的排序方法:Arrays.sort()基本用法排序对数组的影响对字符串数组排序实现降序排序方法1:对基本类型数组先升序再反转方法2:使用包装类和比较器(对象数组)排序算法的选择与性能实际应用案例案例1:对自定义对象数组排序案例2:排序并去重总结
Java数组排序
排序的基本概念与重要性
排序是将一组无序数据按照特定顺序(通常是升序或降序)重新排列的过程。在实际应用中,排序的主要目的包括:
便于数据查找(如二分查找必须基于有序数据)
提高数据展示的可读性
为后续的数据处理(如统计、聚合)提供便利
优化数据存储和传输效率
Java中最常排序的是数组,包括基本类型数组(如int[]、double[])和对象数组(如String[]、自定义对象数组)。
经典排序算法:冒泡排序
冒泡排序是一种简单直观的排序算法,其核心思想是通过重复比较相邻元素并交换位置,使较大的元素逐渐"浮"到数组末尾。
冒泡排序的实现原理
从数组头部开始,依次比较相邻的两个元素
如果前一个元素大于后一个元素,交换它们的位置
完成一轮比较后,最大的元素会移动到数组末尾
忽略已排好序的末尾元素,对剩余元素重复上述过程
直到所有元素都排好序
代码实现:升序排列
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] numbers = {28, 12, 89, 73, 65, 18, 96, 50, 8, 36};
System.out.println("排序前:" + Arrays.toString(numbers));
// 冒泡排序实现
for (int i = 0; i < numbers.length - 1; i++) {
// 每轮循环后,最大的元素已"浮"到末尾,因此减少一次比较
for (int j = 0; j < numbers.length - i - 1; j++) {
// 如果前一个元素大于后一个,交换它们
if (numbers[j] > numbers[j + 1]) {
int temp = numbers[j];
numbers[j] = numbers[j + 1];
numbers[j + 1] = temp;
}
}
}
System.out.println("排序后:" + Arrays.toString(numbers));
}
}
输出结果:
排序前:[28, 12, 89, 73, 65, 18, 96, 50, 8, 36]
排序后:[8, 12, 18, 28, 36, 50, 65, 73, 89, 96]
交换变量的注意事项
在排序过程中,交换两个变量的值需要借助临时变量,否则会导致数据丢失:
// 错误的交换方式
int a = 10;
int b = 20;
a = b; // a现在是20
b = a; // b仍然是20,原始a的值已丢失
// 正确的交换方式
int a = 10;
int b = 20;
int temp = a; // 保存a的原始值
a = b; // a变为20
b = temp; // b变为10
这是排序算法中最基础也最容易出错的环节,必须特别注意。
Java标准库的排序方法:Arrays.sort()
手动实现排序算法虽然有助于理解原理,但在实际开发中,我们更倾向于使用Java标准库提供的排序功能,因为它们通常经过优化,性能更好。
基本用法
Java的java.util.Arrays类提供了sort()方法,可以直接对数组进行排序:
import java.util.Arrays;
public class ArraysSortExample {
public static void main(String[] args) {
int[] numbers = {28, 12, 89, 73, 65, 18, 96, 50, 8, 36};
// 使用标准库排序
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
// 输出:[8, 12, 18, 28, 36, 50, 65, 73, 89, 96]
}
}
Arrays.sort()方法默认对数组进行升序排列,其内部使用的排序算法因数据类型而异:
对于基本类型数组,使用双轴快速排序(Dual-Pivot QuickSort)
对于对象数组,使用TimSort(归并排序的变种)
排序对数组的影响
需要注意的是,Arrays.sort()会直接修改原数组,而不是返回一个新的排序后的数组:
int[] original = {3, 1, 2};
int[] copy = original; // 引用同一个数组
Arrays.sort(original);
System.out.println(Arrays.toString(original)); // [1, 2, 3]
System.out.println(Arrays.toString(copy)); // [1, 2, 3](同样被修改)
这是因为数组是引用类型,original和copy指向内存中的同一个数组对象。
对字符串数组排序
Arrays.sort()同样适用于对象数组,如字符串数组:
import java.util.Arrays;
public class StringSortExample {
public static void main(String[] args) {
String[] fruits = {"banana", "apple", "pear", "orange"};
System.out.println("排序前:" + Arrays.toString(fruits));
Arrays.sort(fruits);
System.out.println("排序后:" + Arrays.toString(fruits));
}
}
输出结果:
排序前:[banana, apple, pear, orange]
排序后:[apple, banana, orange, pear]
字符串排序基于Unicode字符编码的字典顺序,与我们日常使用的字典排序一致。
实现降序排序
Arrays.sort()默认提供升序排序,要实现降序排序,需要额外处理:
方法1:对基本类型数组先升序再反转
import java.util.Arrays;
public class DescendingSort {
public static void main(String[] args) {
int[] numbers = {28, 12, 89, 73, 65, 18, 96, 50, 8, 36};
// 先升序排序
Arrays.sort(numbers);
// 再反转数组
for (int i = 0; i < numbers.length / 2; i++) {
int temp = numbers[i];
numbers[i] = numbers[numbers.length - 1 - i];
numbers[numbers.length - 1 - i] = temp;
}
System.out.println(Arrays.toString(numbers));
// 输出:[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]
}
}
方法2:使用包装类和比较器(对象数组)
对于对象数组(包括基本类型的包装类数组),可以使用带比较器的sort()方法:
import java.util.Arrays;
import java.util.Collections;
public class DescendingSortWithComparator {
public static void main(String[] args) {
// 使用Integer包装类数组
Integer[] numbers = {28, 12, 89, 73, 65, 18, 96, 50, 8, 36};
// 使用Collections.reverseOrder()获取降序比较器
Arrays.sort(numbers, Collections.reverseOrder());
System.out.println(Arrays.toString(numbers));
// 输出:[96, 89, 73, 65, 50, 36, 28, 18, 12, 8]
}
}
这种方法更灵活,适用于需要自定义排序规则的场景。
排序算法的选择与性能
不同的排序算法在性能上有显著差异,了解它们的特点有助于选择合适的算法:
排序算法
平均时间复杂度
最坏时间复杂度
空间复杂度
稳定性
冒泡排序
O(n²)
O(n²)
O(1)
稳定
插入排序
O(n²)
O(n²)
O(1)
稳定
快速排序
O(n log n)
O(n²)
O(log n)
不稳定
归并排序
O(n log n)
O(n log n)
O(n)
稳定
Arrays.sort()(基本类型)
O(n log n)
O(n log n)
O(log n)
不稳定
在实际开发中,除非有特殊需求,否则应优先使用Java标准库的Arrays.sort()方法。
实际应用案例
案例1:对自定义对象数组排序
要对自定义对象数组排序,需要让对象类实现Comparable接口或提供Comparator:
import java.util.Arrays;
// 实现Comparable接口
class Student implements Comparable
String name;
int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
// 按分数升序排序
@Override
public int compareTo(Student other) {
return this.score - other.score;
}
@Override
public String toString() {
return name + "(" + score + ")";
}
}
public class ObjectSortExample {
public static void main(String[] args) {
Student[] students = {
new Student("Alice", 85),
new Student("Bob", 75),
new Student("Charlie", 90)
};
Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 输出:[Bob(75), Alice(85), Charlie(90)]
}
}
案例2:排序并去重
排序后的数据更容易进行去重操作:
import java.util.Arrays;
public class SortAndDeduplicate {
public static void main(String[] args) {
int[] numbers = {5, 3, 8, 3, 5, 1, 8};
// 先排序
Arrays.sort(numbers);
System.out.println("排序后:" + Arrays.toString(numbers));
// 去重
int index = 0;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] != numbers[index]) {
numbers[++index] = numbers[i];
}
}
// 复制去重后的结果
int[] uniqueNumbers = Arrays.copyOf(numbers, index + 1);
System.out.println("去重后:" + Arrays.toString(uniqueNumbers));
}
}
输出结果:
排序后:[1, 3, 3, 5, 5, 8, 8]
去重后:[1, 3, 5, 8]
总结
冒泡排序是理解排序原理的基础,通过重复比较和交换相邻元素实现排序
Java标准库的Arrays.sort()方法是实际开发中的首选,性能优异且使用简便
排序会直接修改原数组(引用类型特性)
升序是默认排序方式,降序排序需要额外处理
不同排序算法各有优劣,应根据数据规模和特性选择合适的算法