Java选择排序:Comparator实现字符串末字符排序
2025-02-28 03:29:04
Java 中使用 Comparator 实现选择排序(Selection Sort)并解决特定问题
最近在写一个程序,需要对字符串列表进行选择排序。程序接收 6 个字符串作为输入,然后按照字符串的最后一个字符对它们进行排序。但我写的代码出了点问题, 这篇文章就来讲讲我是怎么解决这个问题的。
问题
我的程序接收 6 个字符串输入, 应该输出按最后一个字符排序的字符串列表. 可是实际运行结果和期望的不一样。 下面是我尝试的代码和对应的输出:
代码:
import java.util.Arrays;
import java.util.Scanner;
import java.util.List;
import java.util.Comparator;
public class Exercise_20_21 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter 6 strings: ");
// Step 1: proccess strings from input
String data = input.next();
String[] list = data.split(" ");
for (int i = 0; i < list.length; i++) {
System.out.print(list[i] + " ");
}
selectionSort(list, new Comparator<String>() {
@Override
public int compare(String w1, String w2) {
if (w1.charAt(0) > w2.charAt(0)) {
return -1;
} else if (w1.charAt(0) < w2.charAt(0)) {
return 1;
} else {
return 0;
}
}
});
for (int i = 0; i < list.length; i++) {
System.out.print(list[i] + " ");
}
}
public static <E> void selectionSort(E[] list, Comparator<? super E> comparator) {
Arrays.sort(list, comparator);
}
}
期望输出:
Enter 6 strings: red blue green yellow orange pink
red blue orange pink green yellow
实际输出:
Enter 6 strings: red blue green yellow orange pink
red red
问题原因分析
看这输出结果,我发现问题可能出在这几个地方:
- 输入处理:
input.next()
只读取了第一个字符串。遇到空格就停了, 后面的字符串根本没读进去。 - Comparator 的实现: Comparator 比较的是字符串的第一个字符,而不是最后一个字符。
- 排序算法: 虽然代码里写的是
selectionSort
, 但实际上调用的是Arrays.sort()
,这并不是选择排序,而是 Java 内置的排序算法(可能是快速排序或者归并排序)。
解决方案
针对上面分析的原因, 我逐个解决。
1. 修复输入处理
要读取所有输入的字符串,不能只用 input.next()
。 应该用循环读取, 或者先用nextLine()
读取整行,再进行分割。
修改后的代码:
Scanner input = new Scanner(System.in);
System.out.print("Enter 6 strings: ");
String[] list = new String[6];
for (int i = 0; i < 6; i++) {
list[i] = input.next();
}
// 或者用 nextLine()
//Scanner input = new Scanner(System.in);
//System.out.print("Enter 6 strings: ");
//String data = input.nextLine();
//String[] list = data.split(" ");
这样就能保证读取到所有的输入字符串。
2. 修正 Comparator
要按最后一个字符排序,compare
方法里就要比较字符串的最后一个字符。
修改后的代码:
new Comparator<String>() {
@Override
public int compare(String w1, String w2) {
char lastChar1 = w1.charAt(w1.length() - 1);
char lastChar2 = w2.charAt(w2.length() - 1);
if (lastChar1 > lastChar2) {
return 1;
} else if (lastChar1 < lastChar2) {
return -1;
} else {
return 0;
}
}
}
这样, Comparator
就能按字符串的最后一个字符进行比较。
3. 实现选择排序 (Selection Sort)
题目要求是实现选择排序, 所以得把Arrays.sort()
换成自己实现的选择排序算法。
选择排序的原理:
选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
代码实现:
public static <E> void selectionSort(E[] list, Comparator<? super E> comparator) {
int n = list.length;
for (int i = 0; i < n - 1; i++) {
// 找到未排序部分最小元素的索引
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (comparator.compare(list[j], list[minIndex]) < 0) {
minIndex = j;
}
}
// 将最小元素与未排序部分的第一个元素交换
if (minIndex != i) {
E temp = list[i];
list[i] = list[minIndex];
list[minIndex] = temp;
}
}
}
这个 selectionSort
方法就实现了选择排序。每次循环都从未排序的部分里找出最小的元素, 然后和未排序部分的第一个元素交换。
4. 完整的修改后代码
把上面的修改都整合起来,完整的代码是这样的:
import java.util.Comparator;
import java.util.Scanner;
public class Exercise_20_21 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter 6 strings: ");
String[] list = new String[6];
for (int i = 0; i < 6; i++) {
list[i] = input.next();
}
// 或者
//String data = input.nextLine();
//String[] list = data.split(" ");
System.out.print("Input: ");
for (int i = 0; i < list.length; i++) {
System.out.print(list[i] + " ");
}
System.out.println();
selectionSort(list, new Comparator<String>() {
@Override
public int compare(String w1, String w2) {
char lastChar1 = w1.charAt(w1.length() - 1);
char lastChar2 = w2.charAt(w2.length() - 1);
if (lastChar1 > lastChar2) {
return 1;
} else if (lastChar1 < lastChar2) {
return -1;
} else {
return 0;
}
}
});
System.out.print("Output: ");
for (int i = 0; i < list.length; i++) {
System.out.print(list[i] + " ");
}
}
public static <E> void selectionSort(E[] list, Comparator<? super E> comparator) {
int n = list.length;
for (int i = 0; i < n - 1; i++) {
// 找到最小元素的索引
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (comparator.compare(list[j], list[minIndex]) < 0) {
minIndex = j;
}
}
// 将最小元素与未排序部分的第一个元素交换
if (minIndex != i) {
E temp = list[i];
list[i] = list[minIndex];
list[minIndex] = temp;
}
}
}
}
运行结果:
Enter 6 strings: red blue green yellow orange pink
Input: red blue green yellow orange pink
Output: red blue orange pink green yellow
这下,输入、排序逻辑都对了,结果也符合预期。
5. 代码优化和进阶技巧
虽然问题解决了,但还可以做些优化,提升代码质量。
-
Comparator 简化: 可以用
Comparator.comparingInt
来简化 Comparator 的创建。selectionSort(list, Comparator.comparingInt(s -> s.charAt(s.length() - 1)));
更简洁, 也更容易理解。
-
处理空字符串: 如果输入的字符串可能是空的,
charAt
会出错. 可以加个判断.selectionSort(list, (s1, s2) -> { if (s1.isEmpty() && s2.isEmpty()) { return 0; } if (s1.isEmpty()) { return -1; // 空字符串排前面 } if (s2.isEmpty()) { return 1; // 空字符串排前面 } return Integer.compare(s1.charAt(s1.length() - 1), s2.charAt(s2.length()-1)); });
-
更灵活的排序规则: 如果除了按最后一个字符排序, 还想在最后一个字符相同的情况下按其他规则排序 (比如按字符串长度, 或者按字典序), 可以进一步扩展 Comparator.
selectionSort(list, Comparator.comparingInt((String s) -> s.charAt(s.length() - 1)) .thenComparing(String::length) // 如果最后一个字符一样,按长度排序 .thenComparing(Comparator.naturalOrder())); // 如果长度也一样,按字典序
这样一来代码变得更灵活。
以上就是我对这个问题的解决过程和一些思考, 把一个一开始跑不通的小程序,逐步分析、调试,最终解决了问题。也让我对Java 里的 Comparator 和排序算法有了更深的理解。