求助一个自己写程序中的关于TreeSet同时去重和按加入顺序存储的bug。

[复制链接]
查看11 | 回复8 | 2021-1-27 06:09:33 | 显示全部楼层 |阅读模式
昨天在写一个题目其中一块的任务是:将一些字符串去重,并且按给你时候的顺序输出出来,我没有想到用LinkedHashSet,第一想到的是使用TreeSet,故构造一个带comparator的treeset,让俩东西相等时候输出0,表示重复,那么treeset应该会不添加这个新元素,其余情况输出1表示直接添加到末尾,不做交换。然鹅实际情况与我想象的不一样,重复元素出现在特定位置时候无法去除(这一部分我通过debug自己定义的compartatoro1,o2进行了对比已经证实comparator书写正确,是没有进行全遍历而造成的无法识别重复)。为了简单复现这个问题,我书写了加入简单integer类型的treeset,代码如下
publicclassTree{
publicstaticvoidmain(String[]args){
TreeSet[I]treeSet=newTreeSet(newComparator[I](){
@Override
publicintcompare(Integero1,Integero2){
//TODOAuto-generatedmethodstub
if(o1.equals(o2))
{
return0;
}
return1;
}
});
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(1);
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(7);
treeSet.add(1);
treeSet.add(6);
treeSet.add(7);
treeSet.add(1);
for(inti:treeSet)
{
System.out.println(i);
}
}
}
这个代码也许你以为会输出1,2,3,4,5,7,6
但是实际情况是
1
2
3
1
4
5
7
6

根据debug结果可以发现在加入第二个1时候(也就是加入这个1之前是1,2,3),这时候我认为加入1之后o1一直作为1,去和剩余3个元素作对比,如果重复就不会添加,然鹅实际情况再一次不同,o1一直作为1,也就是新添加的元素,只与2,3做了对比(也就是o2元素只遍历了2,3这两个)就结束了,程序发现并没有重复,因为根本就没看开头位置的东西是1,当然认为无重复,就把1又加了进去。
这个同理可以验证到字符串上面,并且更多的试验表明在总长超过6之后下标为2的元素也不会被o2遍历到。
小弟长时间自己思考,百度源码结论都应该是冒泡逐个遍历,但是并没能解决,还请各位老师指点一二。非常感谢!
分 -->
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层

publicclassStudent{
publicstaticvoidmain(String[]args){
TreeSet[I]treeSet=newTreeSet[I](newComparator[I](){
publicintcompare(Integero1,Integero2){
/*if(o1.equals(o2)){
return0;
}
return1;*/
returno1.compareTo(o2);
}
});
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(1);
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(7);
treeSet.add(1);
treeSet.add(6);
treeSet.add(7);
treeSet.add(1);

for(inti:treeSet){
System.out.println(i);
}
}
}

回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
引用1楼bcsflilong的回复:
publicclassStudent{
publicstaticvoidmain(String[]args){
TreeSet[I]treeSet=newTreeSet[I](newComparator[I](){
publicintcompare(Integero1,Integero2){
/*if(o1.equals(o2)){
return0;
}
return1;*/
returno1.compareTo(o2);
}
});
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(1);
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(7);
treeSet.add(1);
treeSet.add(6);
treeSet.add(7);
treeSet.add(1);

for(inti:treeSet){
System.out.println(i);
}
}
}

你这样写returno1.compareTo(o2);是完全排序了,楼主的意思不是要排序,只判重
我看了下,只判重,楼主的cmopare好像是没问题的,但是没想明白为啥结果不对。。。
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层

publicclassTree{
publicstaticvoidmain(String[]args){
TreeSet[I]treeSet=newTreeSet[I](newComparator[I](){
@Override
publicintcompare(Integero1,Integero2){
//TODOAuto-generatedmethodstub
intnum=o1-o2;
returnnum==0?o1.compareTo(o2):num;
}
});
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(1);
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(7);
treeSet.add(1);
treeSet.add(6);
treeSet.add(7);
treeSet.add(1);
for(inti:treeSet){
System.out.println(i);
}
}
}

回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
引用1楼bcsflilong的回复:
publicclassStudent{
publicstaticvoidmain(String[]args){
TreeSet[I]treeSet=newTreeSet[I](newComparator[I](){
publicintcompare(Integero1,Integero2){
/*if(o1.equals(o2)){
return0;
}
return1;*/
returno1.compareTo(o2);
}
});
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);
treeSet.add(1);
treeSet.add(4);
treeSet.add(1);
treeSet.add(5);
treeSet.add(7);
treeSet.add(1);
treeSet.add(6);
treeSet.add(7);
treeSet.add(1);

for(inti:treeSet){
System.out.println(i);
}
}
}

应该是缺少返回值-1吧
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
引用错了程序,楼主缺少返回值-1
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
这里看到一个觉得在理的回答:
因为treeSet的存储是使用treemap来实现的结构为二叉树你的例子中在添加了123三个数之后根结点为2左节点(比父节点小)为1右节点为3在这个时候插入1这个数比较器先与2判断返回1(新插入的1比2大)则继续与3比较也返回1并没有去按照你所想的先与1比较
也就是说你所写的这个比较方法插入同样的数可能会因为不同的插入顺序导致不同的结果。
但是个人还有个问题为啥二叉树进去1.2.3时候是2为根节点而不是1,是因为红黑树的左右旋转调整结果吗
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
引用6楼weixin_42546808的回复:这里看到一个觉得在理的回答:
因为treeSet的存储是使用treemap来实现的结构为二叉树你的例子中在添加了123三个数之后根结点为2左节点(比父节点小)为1右节点为3在这个时候插入1这个数比较器先与2判断返回1(新插入的1比2大)则继续与3比较也返回1并没有去按照你所想的先与1比较
也就是说你所写的这个比较方法插入同样的数可能会因为不同的插入顺序导致不同的结果。
但是个人还有个问题为啥二叉树进去1.2.3时候是2为根节点而不是1,是因为红黑树的左右旋转调整结果吗

因为红黑树小的放左边,大的放右边,负表示小,正表示大,你的比较2个数不相等结果都是1,这时候第2个1被放3的右边,等于树的左右2边都有1,所以后面的1会和放在右边第2个1比较被去重。
回复

使用道具 举报

千问 | 2021-1-27 06:09:33 | 显示全部楼层
红黑树是种平衡树,任意节点左边不为空的话,左边节点连接的所以值都小于该节点,右边都大于该节点
所以放入1,2,3时1在左节点2为根节点,3在有节点。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行