实现 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;
}
如果您想继续使用您的实现来比较 test
和 CandidateTest
,那么您也可以计算唯一哈希值并根据结果做出决定。
这是代码片段:
/* 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++){
这里的问题是 test
和 canidateTest
是您制作的克隆,您正在从这些包中删除元素。并且任何时候你从包中移除一个元素,size
都会减少(因为你减少了 manyItems
和 size()
returns manyItems
)。这意味着你只会通过一半的数组。假设原来的大小是4,那么,第一次通过循环,i==0
和test.size()==4
;第二次,i==0
和 test.size()==3
;第三次,i==2
和 test.size()==2
,然后退出循环。所以您不会查看所有 4 个元素——您只查看 2 个。
您需要决定:要遍历原始数组的元素还是克隆的元素?如果你遍历克隆的元素,你实际上永远不需要增加 i
。你总是可以查看 test.data[0]
,因为一旦你查看它,你就删除了它,所以你知道 test.data[0]
将被替换为其他内容。事实上,您根本不需要 i
。循环直到袋子大小为 0,或者直到您确定袋子不相等。另一方面,如果您遍历 this.data
的元素(即查看 this.data[i]
或只是 data[i]
),则确保 i
一直到 this.size()
.
(还有一个小点:正确的拼写是"candidate"。)
我正在做一项学校作业。 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;
}
如果您想继续使用您的实现来比较 test
和 CandidateTest
,那么您也可以计算唯一哈希值并根据结果做出决定。
这是代码片段:
/* 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++){
这里的问题是 test
和 canidateTest
是您制作的克隆,您正在从这些包中删除元素。并且任何时候你从包中移除一个元素,size
都会减少(因为你减少了 manyItems
和 size()
returns manyItems
)。这意味着你只会通过一半的数组。假设原来的大小是4,那么,第一次通过循环,i==0
和test.size()==4
;第二次,i==0
和 test.size()==3
;第三次,i==2
和 test.size()==2
,然后退出循环。所以您不会查看所有 4 个元素——您只查看 2 个。
您需要决定:要遍历原始数组的元素还是克隆的元素?如果你遍历克隆的元素,你实际上永远不需要增加 i
。你总是可以查看 test.data[0]
,因为一旦你查看它,你就删除了它,所以你知道 test.data[0]
将被替换为其他内容。事实上,您根本不需要 i
。循环直到袋子大小为 0,或者直到您确定袋子不相等。另一方面,如果您遍历 this.data
的元素(即查看 this.data[i]
或只是 data[i]
),则确保 i
一直到 this.size()
.
(还有一个小点:正确的拼写是"candidate"。)