实现 equals() 方法来比较两个 'bag' 对象的内容

Implementing an equals() method to compare contents of two 'bag' objects

我正在做一项学校作业。 objective 用于练习 GUI、clone() 方法以及使用/修改现有代码。 我正在尝试按照讲师的要求编写一个 equals 方法——通过使用对象的克隆,从包中移除物品(returns 布尔值基于移除成功或失败) .

包是用数组表示的,在{1,2,3}和{3,2,1}等情况下应该return为真,即顺序无关紧要,只有数量数组中存在的每个数字。

问题来了

它在大多数情况下都有效,但是在袋子包含这样的数字的情况下存在错误:{1,1,2} 和 {1,2,2} 以及其他类似的迭代。 return是真的而不是假的。

我认为这与我们应该使用的 remove() 方法有关。如果我理解正确,应该将值放在数组的 'end' 处并减少 manyItems 计数器(这是数组中项目数的变量,因为默认情况下 array.length在构造函数中 10.)

代码大部分是别人写的。我们必须导入现有文件并编写新的方法来完成给我们的任务。我已经完成了所有 GUI 部分,所以我不会包括 class,只包括 IntArrayBag class.

中使用的方法

第二双眼睛会很有帮助。谢谢

public class IntArrayBag implements Cloneable
{
// Invariant of the IntArrayBag class:
//   1. The number of elements in the bag is in the instance variable 
//      manyItems, which is no more than data.length.
//   2. For an empty bag, we do not care what is stored in any of data;
//      for a non-empty bag, the elements in the bag are stored in data[0]
//      through data[manyItems-1], and we don�t care what�s in the
//      rest of data.
private int[ ] data;
private int manyItems;

public IntArrayBag( )
{
  final int INITIAL_CAPACITY = 10;
  manyItems = 0;
  data = new int[INITIAL_CAPACITY];
}

public IntArrayBag clone( )
{  // Clone an IntArrayBag object.
  IntArrayBag answer;

  try
  {
     answer = (IntArrayBag) super.clone( );
  }
  catch (CloneNotSupportedException e)
  {  // This exception should not occur. But if it does, it would probably
     // indicate a programming error that made super.clone unavailable.
     // The most common error would be forgetting the "Implements Cloneable"
     // clause at the start of this class.
     throw new RuntimeException
     ("This class does not implement Cloneable");
  }

  answer.data = data.clone( );

  return answer;
}

public int size( )
{
  return manyItems;
}

public boolean remove(int target)
{
  int index; // The location of target in the data array.

  // First, set index to the location of target in the data array,
  // which could be as small as 0 or as large as manyItems-1; If target
  // is not in the array, then index will be set equal to manyItems;
  for (index = 0; (index < manyItems) && (target != data[index]); index++)
     // No work is needed in the body of this for-loop.
     ;

  if (index == manyItems)
     // The target was not found, so nothing is removed.
     return false;
  else
  {  // The target was found at data[index].
     // So reduce manyItems by 1 and copy the last element onto data[index].
     manyItems--;
     data[index] = data[manyItems];
     return true;
  }
}
//I added extra variables that are not needed to try to increase readability,
//as well as when i was trying to debug the code originally
public boolean equals(Object obj){

   if (obj instanceof IntArrayBag){

       IntArrayBag canidate = (IntArrayBag) obj; // i know this can be changed, this was required
       IntArrayBag canidateTest = (IntArrayBag) canidate.clone(); //this was created
       //as a clone because it was otherwise referring to the same memory address
       //this caused items to be removed from bags when testing for equality
       IntArrayBag test = (IntArrayBag) this.clone();

       //fast check to see if the two objects have the same number of items, 
       //if they dont will return false and skip the item by item checking
       if (test.size() != canidateTest.size())
           return false;

       //the loop will go through every element in the test bag it will 
       //then remove the value that is present at the first index of the test bag
       for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
           int check = test.data[i];
           //remove() returns a boolean so if the value is not present in each bag
           //then the conditional will be met and the method will return false
           boolean test1 = test.remove(check);
           boolean test2 = canidateTest.remove(check);
           if (test1 != test2)
               return false;

       }//end for loop

       // if the loop goes through every element
       //and finds every value was true it will return true
       return true;  
   }//end if 
   else
       return false;
}//end equals
}

是否明确说明要使用克隆?您可以通过覆盖此对象的 hashCode() 轻松实现它。

您可以按如下方式覆盖此对象的 hashCode()

@Override
public int hashCode() {
    final int prime = 5;
    int result = 1;
    /* Sort Array */
    Arrays.sort(this.data);
    /* Calculate Hash */
    for(int d : this.data) {
        result = prime * result + d;
    }
    /* Return Result */
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || this.getClass() != obj.getClass()){
            return false;
    }
    return false;
}

如果您想继续使用您的实现来比较 testCandidateTest,那么您也可以计算唯一哈希值并根据结果做出决定。

这是代码片段:

/* Assuming that you have put size comparison logic on top 
   and the two objects are of same size */

final int prime = 31;
int testResult = 1;
int candidateTestResult = 1;
for(int i = 0; i < test.size(); i++) {
    testResult = prime * testResult + test.data[i];
    candidateTestResult = prime * candidateTestResult + candidateTest.data[i];
}
/* Return Result */
return testResult == candidateTestResult;

也许你应该试试SET界面 详细查看:http://www.tutorialspoint.com/java/java_set_interface.htm set 对象不能包含重复的元素,因此它适合您的分配而不是构建您自己的 class.

例如:[1,1,2] 和 [1,2,2] 你可以用它来测试它们是否相等

arr1 = {1,1,2}
arr2 = {1,2,2}
Set<Integer> set = new HashSet<Integer>();
for(int i : arr1){//build set of arr1
    if(set.contains(i)==false){
        set.add(i)
    }
}
for(int i:arr2){
    if(set.contains(i)==false){
        System.out.println('not equal');
        break;
    }
}

希望对您有所帮助。

我看不到全局,因为我以前没有在 Java 中编写 GUI,但是,就比较 2 个 int[] 数组而言,我会在比较之前对数组进行排序。这将允许您消除问题案例,如您所说的(如果可以排序),然后应用类似:

while(array_1[index]==array_2[index] && index<array_1.length)
{index++;}

并通过检查 index

的最终值找到循环在哪里中断

我认为问题出在这一行:

for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){

这里的问题是 testcanidateTest 是您制作的克隆,您正在从这些包中删除元素。并且任何时候你从包中移除一个元素,size 都会减少(因为你减少了 manyItemssize() returns manyItems)。这意味着你只会通过一半的数组。假设原来的大小是4,那么,第一次通过循环,i==0test.size()==4;第二次,i==0test.size()==3;第三次,i==2test.size()==2,然后退出循环。所以您不会查看所有 4 个元素——您只查看 2 个。

您需要决定:要遍历原始数组的元素还是克隆的元素?如果你遍历克隆的元素,你实际上永远不需要增加 i。你总是可以查看 test.data[0],因为一旦你查看它,你就删除了它,所以你知道 test.data[0] 将被替换为其他内容。事实上,您根本不需要 i。循环直到袋子大小为 0,或者直到您确定袋子不相等。另一方面,如果您遍历 this.data 的元素(即查看 this.data[i] 或只是 data[i]),则确保 i 一直到 this.size().

(还有一个小点:正确的拼写是"candidate"。)