TreeSet和TreeMap不能存放重复元素?能不能存放null?其实不是这样的——灵活的二叉树

TreeSet和TreeMap不能存放重复元素?能不能存放null?其实不是这样的——灵活的二叉树

本文链接:https://blog.csdn.net/u010698072/article/details/55255073

问题一:本来认为TreeMap不能存放重复元素?其实并非如此;
其实一般情况下是不允许存放重复元素的,但是它并非这么死板,在一些情况下是可以存放重复元素的,存了又会有引入其他问题。
问题二:能不能存放null呢?正常情况下是不能的,会报异常,但是经过一些处理后是可以的。
解答问题一:
1、存放元素时,TreeMap实现外部比较器接口Comparator,并重写其compare方法,当判断元素重复时,强制compare方法返回一个非0的数,就可以将重复元素存入;

TreeMap<Integer,String> tree = new TreeMap<Integer,String>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                if(o1.equals(o2))
                    return 1;
                else
                return o1-o2;
            }
        });

这种是通过外部比较器进行排序,即是,不通过元素自身的方法来比较,而通过集合实现比较器接口来进行排序。上面代码,通过外部比较器中重写compare方法,判断其返回值来确定排序位置,判断结果有三种:(一)大于0,(二)小于0,(三)等于0;大于0时,表示o1比o2大,因此要排在后面,,小于0时,表示o1比o2小,因此要排在前面,等于0时,集合会认为二者相等,即已经存在此元素了,不再存储(从这一点可以反映出TreeMap集合框架的防止元素重复的机制),但是会对值进行更新(我们的重点不在值)。~~这一点就体现了TreeMap集合的灵活性了,我们如果想存入重复元素,那么就可以控制compare方法的返回值,来达到目的。这样是有效的→→↓↓;
但是???问题来了,比如我们在compare中重写,判断两个元素一样是,强制返回1,元素是存进去了,可是我们在调用get方法去拿出这个元素和其值时,就出问题了,拿到的永远是null,也就是找不到这个元素!不按常规出牌总是要付出代价的,为什么呢??查看底层代码,我们可以发现,get方法取元素同样是根据比较器来取,调用compare方法查找,直到查找到能让compare方法返回0的元素,就判断,这个元素就是我们要找的元素,就将它的值取出来,如果查完了也没有返回0,那么就认为集合中不存在这个键,返回null!
Demo:

TreeMap<Integer,String> tree = new TreeMap<Integer,String>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                if(o1.equals(o2))
                    return 1;
                else
                return o1-o2;
            }
        });
        tree.put(1, "唐僧");
        tree.put(2, "李白");
        tree.put(5, "白居易");
        tree.put(3, "孙悟空");
        tree.put(2, "李黑");
        System.out.println(tree);
        System.out.println("get(1):"+tree.get(1)+" get(2)"+tree.get(2));

输出:
{1=唐僧, 2=李白, 2=李黑, 3=孙悟空, 5=白居易}
get(1):null get(2)null


将compare方法中的equles判断返回值改为0,输出:
{1=唐僧, 2=李黑, 3=孙悟空, 5=白居易}
get(1):唐僧 get(2)李黑


同样的道理,TreeSet其实就是通过TreeMap来实现的,那么其也响应的特性。

—————————————————————————–
解答问题二:
能不能存放null呢?是可以存放的,但是要避免一个问题,避免出现空指针异常,这个问题是很容易出现的;
如果不实现Comparator接口,那么一定会报出空指针异常(有人会问了,不是还可以用元素实现内部比较器接口吗?是可以实现接口,但是实现了后,存入一个空元素也没法调用它里面的compareTo方法。。),如果实现了Comparator接口,通过适当的写法,时可以避免出现空指针异常,并且顺利的将元素存入和取出:

TreeMap<Integer,String> tree = new TreeMap<Integer,String>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                if(o1 !=null&&o2!=null)
                return o1-o2;
                else if(o1 == null&&o2 != null){
                    return -1;
                }else if(o1!=null&&o2==null)
                    return 1;
                else 
                    return 0;
            }
        });
        tree.put(1, "唐僧");
        tree.put(2, "李白");
        tree.put(5, "白居易");
        tree.put(3, "孙悟空");
        tree.put(2, "李黑");
        tree.put(null, "赵信");
        System.out.println(tree);
        System.out.println("get(1):"+tree.get(1)+"  get(2)"+tree.get(null));

输出:
{null=赵信, 1=唐僧, 2=李黑, 3=孙悟空, 5=白居易}
get(1):唐僧 get(2)赵信

原文地址:https://www.cnblogs.com/it-tsz/p/11508041.html