本题要求编写程序,输入若干英文单词,对这些单词按长度从小到大排序后输出。如果长度相同,按照输入的顺序不变。
输入格式:
输入为若干英文单词,每行一个,以#作为输入结束标志。其中英文单词总数不超过20个,英文单词为长度小于10的仅由小写英文字母组成的字符串。
输出格式:
输出为排序后的结果,每个单词后面都额外输出一个空格。
输入样例:
blue
red
yellow
green
purple
#
输出样例:
red blue green yellow purple
一般碰到这个题,第一想法可能就是用排序函数去解决这道题,但是如果存粹使用排序的话还是会有一些漏洞,这个漏洞会在本篇利用快速排序解题中详细说明。
解题:
利用冒泡排序的排序方式,只是交换规则上改用比较两个字符串的长度,前者长度大于后者长度则交换,否则不交换。
代码:
import java.util.*;
public class Main {
public static String a[] = new String [20];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for(int i = 0; i < 20; i ++) a[i] = "";
String s = sc.nextLine();
int i = 0;
while(!s.equals("#")) {
a[i] = s;
i ++;
s = sc.nextLine();
}
Array_mp(a);
for(int k = 0; k < a.length; k ++)
if(a[k].length() != 0)
System.out.print(a[k] + " ");
}
public static void Array_mp(String a[]) {
for(int i = 0; i < a.length - 1; i ++) {
for(int j = 0; j < a.length - i - 1; j ++) {
String temp = "";
if(a[j].length() > a[j + 1].length()) {
temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
}
}
解题:
java自带sort函数运用的是 “综合排序” 大致排序规则是:
sort()是根据需要排序的数组的长度进行区分的:
首先先判断需要排序的数据量是否大于60。
小于60:
使用插入排序,插入排序是稳定的。
大于60的数据量会根据数据类型选择排序方式:
基本类型:使用快速排序。「因为基本类型不需要考虑稳定性」 Object类型:使用归并排序「因为归并排序具有稳定性」
上述问题参考自:详述Java中sort排序函数
由于本题单词数量不超过20个所以sort使用的是插入排序
所以解题方法也非常清晰,重构一下函数的判断规则即可(忘记重构方式可以看我写的:sort 函数排序规则的重写 JAVA):
代码:
import java.util.*;
public class Main {
public static String a[] = new String [20];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for(int i = 0; i < 20; i ++) a[i] = "";
String s = sc.nextLine();
int i = 0;
while(!s.equals("#")) {
a[i] = s;
i ++;
s = sc.nextLine();
}
Arrays.sort(a, 0, a.length, new Comparator<String>() {
public int compare(String a, String b) {
return a.length() - b.length();
}
});
for(int k = 0; k < 20; k ++) if(a[k].length() != 0) System.out.print(a[k] + " ");
}
}
本题排序的是String类,所以不能用简写版的重构方法。
注意:c++的sort函数与java的sort函数并不一样!
解题:
由于快排的性质,它并不能保证两个相同长度的字符串的先后顺序:
例如:
a
bd
c
e
#
利用快排可能得到(选取基准为a):
a e c bd
正解:
a c e bd
由于bd长度大于c的长度,所以以快排的交换规则bd和c会交换。
忘记快排怎么写的可以看我写的:快速排序算法原理 Quicksort —— 图解(精讲) JAVA
幸运的是冒泡排序规则不会破坏这种先后顺序,所以冒泡排序不会错。
至于快排运行的代码就不放出来了,显示结果是有一个测试点不通过,血压飙升。
为什么纯粹用排序算法有漏洞?
归根结底是因为,排序只能判断两个字符串的长度是否一样,但没办法判断他俩谁先被输入。因为快排无法保证这种先后顺序所以快排会错,而冒泡碰巧能不会破坏这种先后顺序所以险胜快排。
解决方法:
根据数组下标的大小加入一些判定规则,以保证相同字符串的先后顺序的维护。
但是加入上述判别方式后又会使代码变得更加繁琐,那么有没有更优雅的方式呢?
答案就在第4部分。
解题思路:
让我们越过上述用排序解题的鸿沟,重新审视本题。
本题要求将英文单词按长度递增输出,长度相同的按先后顺序输出。
这里我们不妨联想一下,一个数组的下标从前往后肯定也是递增的,如果将单词长度与数组下标对应上,那是否也是一种解决本题的方式?
例如:
设立一个 String 类数组 a[ ]
单词blue的长度为4,那么将输入的blue赋给数组下标为4的数组元素即:a[4] = blue;
同理 yellow 长度为5,那么a[5] = yellow;
最后将数组由前往后输出即可。
但是别忘了还有一个问题,如果再输入一个长度也为4的单词abcd又该怎么办?
解决方法也很简单:放在 blue 的后面即可:
即: a[4] = a[4] + abcd
这样就很容易就解决了相同长度单词先后顺序的问题。
最后细节的在两个单词间加上空格,本题就解决了!
代码:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a[] = new String[10];
for(int i = 0; i < 10; i ++) a[i] = "";//初始化。
String s = sc.nextLine();
while(!s.equals("#")) {
if(a[s.length()].length() > 0) a[s.length()] = a[s.length()] + s + " ";
else a[s.length()] = s + " ";
s = sc.nextLine();
}
for(int i = 0; i < 10; i ++) System.out.print(a[i]);
}
}