求助:ArrayList<Book>按numPoints()排序失败,两段实现均有问题
排查两段Book列表排序代码的问题
我来帮你逐个分析这两段代码的问题所在,以及对应的修复方案:
第一段选择排序代码的问题:无法正确排序
这段代码的核心问题有两个:
indMax变量未更新:在内部循环找到更大numPoints()的Book时,你只更新了临时变量mon,但没有同步更新indMax(记录最大值元素的索引)。这导致后续的交换判断if(indMax != i)永远不成立,根本没有执行元素交换操作,自然无法完成排序。- 打印循环变量错误:最后打印列表的循环中,你用了未定义的变量
j(循环变量是s),这会导致编译错误或运行异常。
修复后的第一段代码:
public static void sort() { Book mon = null; int indMax = 0; for(int i=0; i<b.size()-1; i++){ mon = b.get(i); indMax = i; for(int j=i+1; j<b.size(); j++){ if(b.get(j).numPoints() > mon.numPoints()){ mon = b.get(j); indMax = j; // 关键:更新最大值的索引 } } if(indMax != i){ // 交换当前i位置和最大值位置的元素 b.set(indMax, b.get(i)); b.set(i, mon); } } // 修正打印的循环变量 for(int s=0; s<b.size(); s++) { b.get(s).show(); } }
第二段代码的问题:IndexOutOfBoundsException异常
这段代码抛出数组越界异常的原因是**vMax和iMax没有在每次循环中重置**:
第一次循环时,你找到了列表中的最大值,vMax被设为该最大值,iMax是对应的索引。但当你把这个元素从b中移除后,下一次循环时vMax仍然保留着上一次的最大值,而当前b中的所有元素的numPoints()都小于这个值,导致iMax始终不会被更新,仍然是上一次的索引。如果此时b的长度已经小于该索引,就会触发IndexOutOfBoundsException(比如你遇到的Index: 2, Size: 2,说明第二次循环时iMax还是2,但当前b的长度已经是2,索引只能到1)。
修复后的第二段代码:
public static void sort() { ArrayList<Book> o = new ArrayList<Book>(); while(b.size()!=0) { // 每次循环前重置最大值和对应的索引,初始化为当前列表第一个元素 double vMax = b.get(0).numPoints(); int iMax = 0; for(int i = 0; i<b.size(); i++) { if(vMax < b.get(i).numPoints()) { vMax = b.get(i).numPoints(); iMax = i; } } o.add(b.get(iMax)); b.remove(iMax); } for(int j=0; j<o.size(); j++) { o.get(j).show(); } }
额外建议:使用Java内置排序简化代码
其实Java已经提供了非常成熟的排序API,不需要自己手动实现排序算法,这样代码更简洁也更不易出错。比如可以用Comparator按numPoints()降序排序:
public static void sort() { // 按numPoints()从大到小排序 b.sort((book1, book2) -> Double.compare(book2.numPoints(), book1.numPoints())); // 增强for循环打印,更简洁 for(Book book : b) { book.show(); } }
内容的提问来源于stack exchange,提问作者AsYouWereAPx
相关产品推荐
相关产品推荐

