Java 二进制搜索不检测重复项?

Java 二进制搜索不检测重复项?,java,binary-search,Java,Binary Search,我有一系列的物品,卡片,都有字符串名称,所以 卡c1=新卡(“卡”) Card c2=新卡(“其他卡”) 然后我使用快速排序对列表进行排序,然后在添加更多卡片之前尝试二进制搜索以查看卡片是否已经存在 所以 if(cards.contains(c3)=true) //什么都不做 else 卡片。添加(c3) 我的cards.contains方法是 比较器c=新比较器(){ @凌驾 公共整数比较(卡u1,卡u2){ 返回u1.getName().compareTo(u2.getName()); }

我有一系列的物品,卡片,都有字符串名称,所以

卡c1=新卡(“卡”)

Card c2=新卡(“其他卡”)

然后我使用快速排序对列表进行排序,然后在添加更多卡片之前尝试二进制搜索以查看卡片是否已经存在

所以

if(cards.contains(c3)=true)

//什么都不做

else

卡片。添加(c3)

我的cards.contains方法是

比较器c=新比较器(){ @凌驾 公共整数比较(卡u1,卡u2){ 返回u1.getName().compareTo(u2.getName()); } }; 整数指数; index=Collections.binarySearch(卡片、it、c); 如果(索引==-1){ 返回false; }否则{ 返回true; } 但问题是它在搜索卡片数组,找到不在列表中的卡片,然后说它们在,然后说列表中的卡片不在

我试图添加10000张卡片,其中8000张是唯一的,但是contains方法返回2000张唯一的卡片,当我检查列表时,它们甚至不是唯一的

我试着运行未排序的代码,结果只返回了大约4000个结果,同样的问题是重复卡片,当我使用暴力并只使用base.contains时,它可以工作,但速度非常慢


(如果我在帖子中弄错了什么,也很抱歉,这是我第一次在这里发帖)

javadoc声明如下:

使用二进制搜索算法在指定列表中搜索指定对象在进行此调用之前,必须根据指定的比较器(如通过sort(list,comparator)方法)将列表按升序排序。如果未排序,则结果未定义。如果列表包含多个与指定对象相等的元素,则无法保证会找到哪个元素

它还声明它返回:

搜索键的索引(如果它包含在列表中);否则,((插入点)-1)。插入点定义为将键插入列表的点:大于键的第一个元素的索引,或list.size()如果列表中的所有元素都小于指定的键。请注意,这保证了当且仅当找到键时,返回值将>=0

因此,您的列表应该事先排序,否则它将不会返回任何有意义的内容。然后,它返回元素的索引或插入点。当心这个技术性问题。执行后,您应该检查索引处的元素是否实际上是正确的,而不仅仅是插入元素的索引
it

在那里,您可以进行此测试,以查看它是否是您的卡:

//测试找到索引处的卡是否与实际查找的卡同名。
回来!index==cards.length&&cards[index].getName().equals(it.getName());
您还可以覆盖
equals
,使其更接近:

返回!index==cards.length&&cards[index]。等于(it);

在这两种情况下,如果插入点位于列表的末尾,我们确保不会出现
ArrayOutOfBoundException

javadoc声明如下:

使用二进制搜索算法在指定列表中搜索指定对象在进行此调用之前,必须根据指定的比较器(如通过sort(list,comparator)方法)将列表按升序排序。如果未排序,则结果未定义。如果列表包含多个与指定对象相等的元素,则无法保证会找到哪个元素

它还声明它返回:

搜索键的索引(如果它包含在列表中);否则,((插入点)-1)。插入点定义为将键插入列表的点:大于键的第一个元素的索引,或list.size()如果列表中的所有元素都小于指定的键。请注意,这保证了当且仅当找到键时,返回值将>=0

因此,您的列表应该事先排序,否则它将不会返回任何有意义的内容。然后,它返回元素的索引或插入点。当心这个技术性问题。执行后,您应该检查索引处的元素是否实际上是正确的,而不仅仅是插入元素的索引
it

在那里,您可以进行此测试,以查看它是否是您的卡:

//测试找到索引处的卡是否与实际查找的卡同名。
回来!index==cards.length&&cards[index].getName().equals(it.getName());
您还可以覆盖
equals
,使其更接近:

返回!index==cards.length&&cards[index]。等于(it);

在这两种情况下,如果插入点位于列表的末尾,我们将确保不会出现
ArrayOutOfBoundException

binarySearch在查找项时提供非负索引

它给出插入位置的补码:~index==-index-1(如果找不到)

  • 在a b d e中搜索d得到2
  • 在BEG中搜索d得到~2==-3,插入位置为2
所以支票是:

int index = Collections.binarySearch(cards, it, c);
return index >= 0;
此外,卡应具有正确的等式:

public class Card implements Comparable<Card> {

    ...

    @Override
    public int compareTo(Card other) {
        return name.compareTo(other.name);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceOf Card)) {
            return false;
        }
        Card other = (Card) obj;
        return name.equals(other.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }
}
公共类卡实现可比性{
...
@凌驾
公共int比较(卡其他){
返回name.compareTo(其他.name);
}
@凌驾
公共布尔等于(对象obj){
如果(!(卡的obj实例)){
返回false;
}
卡其他=(卡)obj;