【问题标题】:stuck with a malfunctioning while loop卡在有故障的while循环中
【发布时间】:2018-12-20 21:01:32
【问题描述】:

我在家庭作业中被这个问题困扰了很长时间,非常感谢您的专业帮助。 我需要模拟填充用于“火星任务”的火箭,其中各种物品已经排列在数组列表中。每个火箭包括货物的最大重量是给定的(18,000 Kg),以及火箭净重(10,000 Kg)和每个项目的重量(项目对象包括字段“重量”和“项目类型”,例如“建筑材料”、“水”等。)

说明是填充每个火箭直到它完全加载,然后才能创建另一个。我的同学似乎忽略了这条指令,所以他们的代码无济于事。

按照权重升序/降序对数组进行排序并不能解决问题。

我的问题是,尽管我已经使用了 while 循环,但火箭拒绝填满,尽管仍有剩余空间可以填充列表中的项目。循环不会跳过接下来的 2-3 项(我设法得到最多的是跳过一项)并找到仍然可以加载的一项。

下面也是项目列表。

public ArrayList<U1> loadU1(ArrayList<Item> items) {

    ArrayList<U1> fleetU1 = new ArrayList();

    int i = 0;

    Iterator<Item> iterator = items.iterator();
    while (iterator.hasNext()) {

        U1 rocketU1 = new U1(); // create new rocket with zero cargo

         while (rocketU1.canCarry(items.get(i))) { // "canCarry" checks if item's weight fits in:

/* public final boolean canCarry(Item cargo){
        if(currentRocketWeight + cargo.weight <= maxRocketWeight){
            return true;
        } else {
            return false; }} */


 rocketU1.carry(items.get(i));

// "carry" updates rocket total weight - no more than 18000 Kg including rocket net weight 10000 Kg, i.e. max cargo weight is 8000 Kg:

/* public final int carry(Item cargo){
           currentRocketWeight += cargo.weight;
           return currentRocketWeight;}
      */
           items.remove(i); // remove loaded item from list

          }

        fleetU1.add(rocketU1); // add rocket to fleet
    }

    return fleetU1;
}

/*arraylist "items" - "phase-1.txt":

building tools=2000
building tools=2000
building tools=2000
building tools=5000
building tools=5000
building tools=2000
building tools=1000
building tools=5000
building tools=6000
shelter equipment=5000
construction equipment=5000
plants=1000
steel=8000
books=1000
water=5000*/

public ArrayList<Item> loadItems(int phaseNum) {

try {
        switch (phaseNum) {
            case 1:
                out.println("Loading phase 1:");
                fileName = "phase-1.txt";
                break;
            case 2:
                out.println("Loading phase 2:");
                fileName = "phase-2.txt";
                break;
            default:
            out.println("argument must be 1 or 2");
        }

        File file = new File(fileName);
        Scanner scanner = new Scanner(file);

        while (scanner.hasNextLine()) {
            lineFromFile = scanner.nextLine();

            String[] list = lineFromFile.split("=");
            Item item = new Item(); //(list[0], );
            item.itemType = list[0];
            item.weight = Integer.parseInt(list[1]);

            itemList.add(item); // create ArrayList of items
        }

        scanner.close();

    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return itemList;

}

【问题讨论】:

  • 你确定你正确使用了迭代器吗?如果您不调用 iterator.next(),iterator.hasNext() 将始终为真。并且您使用 remove 修改支持集合,这将导致 ConcurrentModificationException。那个索引是干什么用的?您的代码根本没有任何意义,因为您混淆了循环概念。请看Iterator
  • @Meini 我什么都不确定。这是我的第一个迭代器,在 whiles 和 ifs 失败之后。索引 i 用于检索列表中每个项目的权重,之前已经增加,但这也无济于事。我一直在尝试很多方法来解决这个问题,所以难怪这看起来很乱。另外我真的是一个初学者,我自己学习,从这个网站也学到了很多东西。感谢您的反馈...
  • 需要使用迭代器吗?使用增强的 for 循环使事情变得更容易编写和阅读:for (Item item : items) { /* do stuff with current item, or break to exit */ }
  • @tucuxi,不,不一定。绝望地尝试过......他们实际上在课程中说循环遍历 ArrayList 的最佳方法是通过“for”循环。会试试你的增强版。

标签: java while-loop


【解决方案1】:

您需要迭代每个火箭的项目。

// create a copy of the items so we can remove without harm to the caller
List<Items> ourList = new ArrayList<>(items);
// you should probably sort the list by weight, descending order

while (!ourList.isEmpty()) {
    // we need a rocket.
    U1 rocket = new U1();
    // go through all the items and load if item fits
    Iterator<Item> iterator = ourList.iterator();
    while (iterator.hasNext()) {
        // the next() call that's mentioned in the comment
        Item item = iterator.next();
        if (rocket.canCarry(item)) {
            rocket.carry(item);
            // you need to remove from the iterator itself, not from the list
            // or you will get an exception because that makes the iterator invalid
            // it will remove from the underlying list as well though
            iterator.remove();
        }
    }
    fleet.add(rocket);
}

【讨论】:

  • 谢谢大牛。我感谢您的帮助。这段代码的问题是我第一次遇到 Meini 警告过的:ConcurrentModificationException。
  • @tucuxi Yes, you can modify a list while iterating。正如我在答案的评论中所写,您确实需要调用迭代器的remove(),而不是底层集合。
  • @Meravi 我不知道你的问题是什么,runs fine for me
  • @daniu oops - 关于迭代和调用 remove(),您是对的,我想推翻我的投票,但似乎我必须等待这样做(或者直到您编辑问题)。
【解决方案2】:

您需要一种方法来填充火箭,然后在仍有货物要装载的情况下循环调用该方法。为了在没有递归调用的情况下完成这项工作,我将火箭数组“fleet”更改为类成员

private List<Item> loadRocket(List<Item> items) {        
    Iterator<Item> iterator = items.iterator();
    List<Item> loaded = new ArrayList<>();
    U1 rocketU1 = new U1();

    while (iterator.hasNext()) {
        Item item = iterator.next();
        if (rocketU1.canCarry(item)) {
            rocketU1.carry(item);
            loaded.add(item);
        } 
    }
    items.removeAll(loaded);
    fleetU1.add(rocketU1);
    return items;
}

然后循环调用它

while (!items.isEmpty()) {
    items = loadRocket(items);
}

如果您不想使用 ´fleetas a class member you could move the creation of the rocket and adding to thefleetlist to outside of ´loadRocket 并将其作为参数发送。

while (!items.isEmpty()) {
    U1 rocket = new U1();
    items = loadRocket(rocket, items);
    fleet.add(rocket);
}

【讨论】:

  • 这正是我们遇到的问题currentRocketWeight &lt; maxRocketWeight 最有可能签入canCary。顺便说一句,问题在于没有更新i
  • @talex,canCarry 不同。我确实注意到了双 while 循环以及发布后如何使用迭代器。需要调查一下。
  • 这看起来很有希望,午饭后会试一试,让你知道它是如何工作的。非常感谢。
  • 你摇滚 :-) 它有效! (我知道这是一个很长的午休时间)。我做的有点不同,因为要求是使用一个“loadU1”方法来返回满载火箭的列表:
  • List loadU1(List items) { Collections.sort(items, new SortLists()); // 按权重降序排序列表 while (!items.isEmpty()) { Iterator iterator = items.iterator(); List 已加载 = new ArrayList(); U1 火箭U1 = 新 U1(); while (iterator.hasNext()) { Item item = iterator.next(); if (rocketU1.canCarry(item)) { rocketU1.carry(item);加载。添加(项目); }} items.removeAll(加载);舰队U1.add(火箭U1); } 返回车队U1; }
【解决方案3】:

所以我会这样做:

对于每个项目,我都会尝试将其放置在舰队中已经存在的火箭中;如果不可能,我会在舰队中增加一枚新火箭。如果该项目即使在空火箭中也无法容纳,则将其保留在输入列表中,否则将其删除:

public List<U1> loadU1(List<Item> items) {
    List<U1> fleetU1 = new ArrayList<>();
    Iterator<Item> iterator = items.iterator();
    while (iterator.hasNext()) {
        Item item = iterator.next();
        U1 rocketU1 = null;
        for (U1 u1: fleetU1) {
            if (u1.canCarry(item)) {
                rocketU1 = u1;
                break;
            }
        }
        if (rocketU1 == null) {
            rocketU1 = new U1();
            if (!rocketU1.canCarry(item)) {
                // the item is too heavy
                continue;
            }
            fleetU1.add(rocketU1);
        }
        rocketU1.carry(item);
        iterator.remove();
    }
    return fleetU1;
}

【讨论】:

  • 请注意,获得的解决方案不一定是最优的:它取决于列表中项目的顺序。
  • 另外,如果到达continue,这将导致无限循环,因为该项目永远不会从被迭代的列表中删除。
  • @daniu 你错了:是iterator.next() 推动了迭代器。
  • 你是对的,项目列表最终不会是空的,但我想这不是手头问题的真正问题。
  • @daniu 最后,列表将包含太重而无法放入火箭的物品。有道理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
  • 2014-03-17
相关资源
最近更新 更多