为何我的For循环忽略了满足条件的乘客分组元素?
乘客分组排序错误的原因与修复方案
问题背景
分组规则如下(优先级从高到低,1组在列表开头,8组在末尾,优先级编号103到1):
- 1组:Type H
- 2组:Type E 且 Row 1-4
- 3组:Type G 且 Row 1-4
- 4组:Type E 或(Type G 且 Row 10/11)
- 5组:Type G 且 Row 23-26
- 6组:Type G 且 Row 17-22
- 7组:Type G 且 Row 11-16(Row11的G已被4组处理)
- 8组:Type G 且 Row 5-10
核心错误原因
1. ArrayList正序遍历删除导致索引遗漏
所有分组循环采用正序遍历ArrayList并直接删除元素,会触发索引错位:删除i位置元素后,后续元素自动前移一位,但循环变量i继续自增,直接跳过了原本位于i+1位置的元素,导致该元素未被检查是否符合当前组条件。
比如Estes(Type E,Row7)本该属于第4组,但遍历第4组时,前面元素被删除后Estes的索引前移,却被循环变量跳过,最终被错误分到后续组。
2. 外层while循环的冗余执行
外层while (!list.isEmpty())会重复执行所有分组循环,第一次循环遗漏的元素,第二次执行时可能被错误匹配到前面组的条件,进一步打乱分组顺序(比如剩余Type E元素会被再次处理,但此时优先级编号已大幅降低)。
3. 部分分组条件的隐含漏洞
第4组的条件代码Type E || Row10 || Row11未明确限制Row10/11的元素必须是Type G,虽然当前数据不会出问题,但如果后续出现其他类型的Row10/11元素,会被错误分到第4组。
修复方案
方案1:使用迭代器安全遍历删除
迭代器是Java中遍历并删除集合元素的标准安全方式,不会出现索引错位:
public void loadOldPQ(ArrayList<Passenger> list) throws IOException { int priorityNumber = list.size(); // 处理1组:Type H Iterator<Passenger> iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("H")) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理2组:Type E 且 Row1-4 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("E") && p.getRow() >= 1 && p.getRow() <= 4) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理3组:Type G 且 Row1-4 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 1 && p.getRow() <= 4) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理4组:Type E 或 (Type G 且 Row10/11) iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("E") || (p.getType().equalsIgnoreCase("G") && (p.getRow() == 10 || p.getRow() == 11))) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理5组:Type G 且 Row23-26 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 23 && p.getRow() <= 26) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理6组:Type G 且 Row17-22 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 17 && p.getRow() <= 22) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理7组:Type G 且 Row11-16 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 11 && p.getRow() <= 16) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } // 处理8组:Type G 且 Row5-10 iterator = list.iterator(); while (iterator.hasNext()) { Passenger p = iterator.next(); if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 5 && p.getRow() <= 10) { p.setKey(priorityNumber--); oldPQ.add(p); iterator.remove(); } } oldProcedure(oldPQ); }
方案2:倒序遍历ArrayList
如果不想使用迭代器,可采用倒序遍历,删除元素后不会影响前面未遍历的元素索引:
// 示例:处理1组的倒序遍历逻辑 for (int i = list.size() - 1; i >= 0; i--) { Passenger p = list.get(i); if (p.getType().equalsIgnoreCase("H")) { p.setKey(priorityNumber--); oldPQ.add(p); list.remove(i); } }
方案3:基于优先级分组的排序优化
更简洁的方式是先给每个乘客分配组优先级,再通过排序完成分组,避免多次遍历删除:
public void loadOldPQ(ArrayList<Passenger> list) throws IOException { // 为每个乘客分配组优先级(组号越小,优先级越高) for (Passenger p : list) { int group; if (p.getType().equalsIgnoreCase("H")) { group = 1; } else if (p.getType().equalsIgnoreCase("E") && p.getRow() >= 1 && p.getRow() <= 4) { group = 2; } else if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 1 && p.getRow() <= 4) { group = 3; } else if (p.getType().equalsIgnoreCase("E") || (p.getType().equalsIgnoreCase("G") && (p.getRow() == 10 || p.getRow() == 11))) { group = 4; } else if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 23 && p.getRow() <= 26) { group = 5; } else if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 17 && p.getRow() <= 22) { group = 6; } else if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 11 && p.getRow() <= 16) { group = 7; } else if (p.getType().equalsIgnoreCase("G") && p.getRow() >= 5 && p.getRow() <= 10) { group = 8; } else { group = 9; // 异常情况默认最低优先级 } p.setKey(100 - group); // 用组号映射临时优先级,后续再调整为连续编号 } // 按临时优先级降序排序 Collections.sort(list, (a, b) -> Integer.compare(b.getKey(), a.getKey())); // 重新赋值连续的优先级编号103到1 int priority = 103; for (Passenger p : list) { p.setKey(priority--); oldPQ.add(p); } oldProcedure(oldPQ); }
内容的提问来源于stack exchange,提问作者fkaman
相关产品推荐
相关产品推荐

