简体   繁体   English

列表过程中的无限循环

[英]Infinite loop in a list procedure

I have the following block of code: 我有以下代码块:

ArrayList<ELPERouteStop> candidates = new ArrayList<>();
    for (int i=0; i < metric.length;i++) 
    {

        /*
         * We get a from object for each row (customer) and a to object for the element
         * of the matrix with the highest metric from the ith customer.
         */
        ELPERouteStop from = all_stops.get(i);
        ELPERouteStop to = all_stops.get(getMaxValue(metric[i]));
        if(i==0)
        {   
            candidates.add(from);
            candidates.add(to);
        }
        for (int j=0; j < candidates.size();j++)
        {
            int k=0;
            if (candidates.get(j) == from || candidates.get(j)==to) 
            {
                k++;
            }
            if (k == 0)
            {
                candidates.add(from);
                candidates.add(to);
            }
        }
    }

What seems to be the problem is the change of size of the candidates list at each iteration. 问题似乎在于每次迭代时候选列表的大小都会发生变化。 I need to insert the from and to objects to the candidates list, only if they don't exist already. 我需要将from和to对象插入候选列表,仅当它们尚不存在时。 Hence, I do the check in the second for loop. 因此,我在第二个for循环中进行检查。 When I run the code it appears to enter an infinite loop and I cannot find why. 当我运行代码时,它似乎进入了无限循环,而我找不到原因。 Thank you in advance! 先感谢您!

You can use Collection#contains instead of iterating the collection each time. 您可以使用Collection#contains而不是每次都迭代集合。

List<ELPERouteStop> candidates = new ArrayList<>();
for (int i=0; i < metric.length;i++) {

    ELPERouteStop from = all_stops.get(i);
    ELPERouteStop to = all_stops.get(getMaxValue(metric[i]));

    if (!candidates.contains(from) && !candidates.contains(to)) {
        candidates.add(from);
        candidates.add(to);
    }
}

Or, slightly more efficient - depending on how fast getMaxValue is: 或者,效率更高一点-取决于getMaxValue速度:

for (int i=0; i < metric.length;i++) {

    ELPERouteStop from = all_stops.get(i);
    if (!candidates.contains(from)) {
        ELPERouteStop to = all_stops.get(getMaxValue(metric[i]));
        if (!candidates.contains(to)) {
            candidates.add(from);
            candidates.add(to);
        }
    }
}

Reason for infinite loop is this conditional statement if (candidates.get(j) == from || candidates.get(j)==to) . 无限循环的原因是条件语句if(candidates.get(j)== from ||候选人.get(j)== to) As you are using == operator to compare the objects it always returns false because == operator always used to compare the reference of the objects not the values. 当您使用==运算符比较对象时,它总是返回false,因为==运算符总是用于比较对象的引用而不是值。 So k value is increasing exponentially on every iteration so that it leads to infinte looping. 因此,k值在每次迭代中都呈指数增长,从而导致无限循环。 for more details about the == and equals() method 有关==和equals()方法的更多详细信息

Solution: 解:

To compare the objects in collection you can use contains() . 要比较集合中的对象,可以使用contains() But for comparing objects you need to override the equals method in ELPERouteStop class. 但是,为了比较对象,您需要重写ELPERouteStop类中的equals方法

For sample refer: 有关示例,请参阅:

class Test{ 班级考试{

String a;

Test(String a){
    this.a = a;
}
@Override
public boolean equals(Object obj) {
        return (this.a.equals( ((Test)obj).a));
}

} }

public static void main(String[] args) { 公共静态void main(String [] args){

    ArrayList<Test> arr = new ArrayList<Test>(4); 

    Test a = new Test("abc");

    arr.add(new Test("abc")); 

    boolean test = a == new Test("abc"); // Returns false due to reference checking

    boolean ans = arr.contains(a); // returns true as this checks with the value  

} }

I need to insert the from and to objects to the candidates list, only if they don't exist already. This seems like a good candidate for a Set . 这似乎是Set的不错候选人。 You could try to use a Set instead of a List and let the data structure itself implement that constraint for you. 您可以尝试使用Set而不是List ,让数据结构本身为您实现该约束。 If you go with that approach, make sure you override the equals and hashCode methods for your objects. 如果采用这种方法,请确保为对象覆盖equalshashCode方法。

In case order matters: 如果订单很重要:

ArrayList<ELPERouteStop> candidates = new ArrayList<>();
        for (int i=0; i < metric.length;i++) 
        {

            /*
             * We get a from object for each row (customer) and a to object for the element
             * of the matrix with the highest metric from the ith customer.
             */
            ELPERouteStop from = all_stops.get(i);
            ELPERouteStop to = all_stops.get(getMaxValue(metric[i]));
            if(i==0)
            {   
                candidates.add(from);
                candidates.add(to);
            }
            else if(!candidates.contains(from)&&!candidates.contains(to))
            {
                    candidates.add(from);
                    candidates.add(to);
            }
        }

In case order doesn't matter: 如果顺序无关紧要:

Set<ELPERouteStop> candidates = new hashset<>();
        for (int i=0; i < metric.length;i++) 
        {

            /*
             * We get a from object for each row (customer) and a to object for the element
             * of the matrix with the highest metric from the ith customer.
             */
            ELPERouteStop from = all_stops.get(i);
            ELPERouteStop to = all_stops.get(getMaxValue(metric[i]));
       //comment out to optimize
            //if(i==0)
            //{   
            //  candidates.add(from);
            //  candidates.add(to);
            //}
              candidates.add(from);
             candidates.add(to);
        }

Since both the loops are for-loop, it's impossible that you enter an infinite loop. 由于两个循环都是for循环,因此不可能输入无限循环。

are you sure that the program was stopped in this block ? 您确定该程序已在此块中停止吗?

I guess it is perhaps just because of low performance making it seems like an infinite loop, try to decrease the size of metric and run again to see if the program can stop. 我想这可能只是由于性能低下导致它看起来像一个无限循环,请尝试减小metric的大小,然后再次运行以查看程序是否可以停止。

Also you can use Set to optimize your code like this: 您也可以使用Set来优化代码,如下所示:

// first declare a set:
Set<int> candidatesSet = new HashSet<>();

// and after added each from/to to `candidates`
candidatedSet.add(from.hashCode())

// replace you second loop with
if (!candidatedSet.contains(from.hashCode()) && !candidatedSet.contains(to.hashCode())) {
    candidates.add(from);
    candidates.add(to);
    candidatedSet.add(from.hashCode());
    candidatedSet.add(to.hashCode());
}

Of course, you need to make sure that you hashCode returns distinct int for each different candidate 当然,您需要确保hashCode 为每个不同的候选者返回不同的int

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM