0 0

TreeSet 的 contains 问题10

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {
 
	public void testCompare(){
		Map<String,String> m1 = new HashMap<String,String>();
		m1.put("AC029", "SE.mg");
		
		Map<String,String> m2 = new HashMap<String,String>();
		m2.put("OS05M", "USD");
		
		Map<String,String> m3 = new HashMap<String,String>();
		m3.put("OS01W", "Stratic Energy Corp");
		m3.put("OS001", "SE");
		m3.put("LS01Z", "EX$$$$XTSX");
		m3.put("OS06Y", "0P00005RTY");
		m3.put("AA0B5", "0C00000KDB");
		m3.put("ST735", "IG000DA093");
		
		Map<String,String> m4 = new HashMap<String,String>();
		m4.put("OS01W", "Spectra Energy Corp");
		m4.put("OS05K", "847560109");
		
		Map<String,String> m5 = new HashMap<String,String>();
		m5.put("OS01W","Spectra Energy Corp");
		m5.put("OS05K","847560109");
		m5.put("OS05J","US8475601097");
		m5.put("AA0B5","0C00000MIG");
		m5.put("IT152","309");
		m5.put("AA0F4","3");
		m5.put("ST735","IG000DA096");
		m5.put("OS05M","USD");
		
		Map<String,String> m6 = new HashMap<String,String>();
		m6.put("OS01W","Spectra Energy Corp");
		m6.put("OS05K","847560109");
		m6.put("LS01Z","EX$$$$XNYS");
		m6.put("OS00I","0P00007KRO");
		m6.put("AC020","SPECTRA ENERGY Corp");
		m6.put("AA0B5","0C00000MIG");
		m6.put("ST735","IG000DA096");
		
		Map<String,String> m7 = new HashMap<String,String>();
		m7.put("OS01W","Spectra Energy Corp");
		m7.put("OS05K","847560109");
		m7.put("AC020","SPECTRA ENERGY Corp");
		m7.put("AA0B5","0C00000MIG");
		m7.put("ST735","IG000DA096");
		
		Map<String,String> m8 = new HashMap<String,String>();
		m8.put("OS01W","Spectra Energy Corp");
		m8.put("OS05K","847560109");
		m8.put("LS01Z","EX$$$$XNYS");
		m8.put("AA0B5","0C00000MIG");
		m8.put("ST735","IG000DA096");
		m8.put("OS05M","USD");
		
		Set<Map<String,String>> set = new TreeSet<Map<String,String>>(new HashCompare());
		set.add(m1);
		set.add(m2);
		set.add(m3);
		set.add(m4);
		set.add(m5);
		set.add(m6);
		set.add(m7);
		set.add(m8);
		
		System.out.println(set.contains(m3));
	}
	
	class HashCompare implements Comparator{

		public int compare(Object o1, Object o2) {
			return o1.hashCode() - o2.hashCode();
		}
	}
	
	public static void main(String[] args) {
		TreeSetTest ts = new TreeSetTest();
		ts.testCompare();
	}
}
 
2014年9月17日 18:33

3个答案 按时间排序 按投票排序

0 0

采纳的答案

首先treeset的contains方法
使用的是Treemap的containskey的方法
实际使用的就是getEntryUsingComparator,基于comparator的二叉树遍历
通过你这里实现的compare来查找是否有与之对应的类

通过上面的信息,了解到最后一步其实找treeSet放置的元素的hashcode
回到HashMap的hashcode这里

HashMap的hashcode实现比较绕
hashcode = sum(entry.hashcode)//所有的entry的hashcode的和

entry.hashcode= key.hashcode^value.hashcode//key的hashcode和value的hashcode 异或操作

这里发现hashcode的值一定不会有问题,那么比较大小一定不会有问题

那为什么contains会找不到元素呢,其实因为因为楼主对treemap(TreeSet底层、红黑树)的结构不了解,遍历的时候因为值的大小问题遍历导致,这里不详细说明红黑树了,可以自行查看

其实本质是因为 hashcode可以为负数,那么大小的判断就会有误,从而二叉树那里除了问题。修改一下代码即可

class HashCompare implements Comparator<Map>{  

		@Override
		public int compare(Map o1, Map o2) {
			int h1 = o1.hashCode();
			int h2 = o2.hashCode();
			if(h1>h2){
				return 1;
			}else if(h1<h2){
				return -1;
			}
			return 0;
		}  
    } 


2014年9月18日 14:12
0 0

因HashCompare 参与构造树和 查找树,所以按照kidding87 的做法是正确的。

2014年9月19日 11:58
0 0


按照楼主自定义的comparetor对比,画出来的树是:

      m1
    m2  m3
  m4
m5  m6
   m8 m7
   
可以看出是一个排序二叉树
其定义很简单:(1)非叶子节点至少一边的分支非NULL;(2)叶子节点左右分支都为NULL;(3)每一个节点记录一个数据,同时左分支的数据都小于右分支的数据。
对于这个问题: 数据只得是hashcode。



那么 contain是如何查找的呢?其实是:m7 ==> m4 ==》M5


结论:

1、一直m3的hashcode(m3: 2076073718),从二叉树结叶子结点 按照 自定义的 HashCompare 去查找, 分别按照 减法对比hashcode,
      最后找错了,路径,返回null,boolean是false。
2、HashCompare 非常重要,参与构造树,以及查找树。



一下是java源代码跟踪部分:

m1: 117608867
m2: 75431906
m3: 2076073718
m4: -1655436036
m5: -1981877973
m6: -1086123974
m7: -952394827
m8: -1639907518
			
Comparator<? super K> cpr = comparator;
if (cpr != null) {
    do {
        parent = t;
        cmp = cpr.compare(key, t.key);
        if (cmp < 0)
            t = t.left;
        else if (cmp > 0)
            t = t.right;
        else
            return t.setValue(value);
    } while (t != null);
}



调用包含的时候: 你可以在TreeSet中加一个断点看看,此处的m是TreeMap,所以
 public boolean contains(Object o) {
	return m.containsKey(o);
    }

调用treeMap中的containsKey方法
public boolean containsKey(Object key) {
  return getEntry(key) != null;
}

相应的getEntry方法。
 final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
	Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }
    
因为:getEntry()方法中:comparator 不为null,此处为 自定义的 HashCompare
if (comparator != null)
            return getEntryUsingComparator(key);
            
所以它又调用了 getEntryUsingComparator 方法,注意 此处的key其实是m3, 该方法里面的comparator还是HashCompare

final Entry<K,V> getEntryUsingComparator(Object key) {
	K k = (K) key;
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            Entry<K,V> p = root;
            while (p != null) {
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;
            }
        }
        return null;
    }

2014年9月19日 11:57

相关推荐

    TreeSet 红黑树结构算法

    TreeSet 的其他方法,如 contains、remove、size 等,也都是调用 TreeMap 的对应方法来实现。 红黑树数据结构是 TreeSet 的核心,它是一种自平衡的排序二叉树。红黑树的每个节点都有一个颜色,要么是红色,要么是...

    java 集合框架(TreeSet练习)

    3. **基本操作**:`add()`用于向`TreeSet`中添加元素,`remove()`用于删除指定元素,`contains()`用于检查集合是否包含某个元素。`clear()`则可以清空整个集合。 4. **迭代器**:`TreeSet`遵循Java集合框架的迭代...

    javaTreeSet实现图书管理系统

    使用`TreeSet`的`contains()`方法查找特定书籍是否已被借出,如果在持卡人的`TreeSet`中找到,就表示已被借出。遍历持卡人集合,找出借阅过这本书的所有记录。 5. **查询借书卡的借出记录** 遍历持卡人`TreeSet`...

    List 去重的6种方法(contains、迭代、hashSet、treeSet、linkedHashSet、stream)

    比较遗憾的是,TreeSet 虽然实现起来也比较简单,但它有着和 HashSet 一样的问题,会自动排序 5:LinkedHashSet去重(有序) 从代码和执行结果可以看出,LinkedHashSet 是到目前为止,实现比较简单,且最终生成的新...

    Java中AVL平衡二叉树实现Map_(仿照TreeMap和TreeSet)1

    6. containsValue()方法:containsValue()方法判断Map中是否包含指定的值。 7. get()方法:get()方法返回指定键对应的值。 8. putAll()方法:putAll()方法将另一个Map中的键值对添加到当前Map中。 四、AVL树在Map中...

    java.Set(处理方案示例).md

    Set接口本身不提供任何实现细节,具体实现需要借助其子类,如HashSet和TreeSet等。在使用Set接口时,开发者常常遇到的问题包括如何添加、删除和遍历元素等。下面是对这些问题的详细分析和解决方案。 首先,向Set中...

    Set实现类1

    它有多种实现类,如HashSet和TreeSet,每个类都有其特定的特性和用途。 1. **HashSet** - **构造函数**:HashSet提供了多种构造方法,包括无参构造、接受Collection参数的构造以及指定初始容量和加载因子的构造。...

    java集合、常用类和String[参照].pdf

    TreeSet&lt;String&gt; treeSet = new TreeSet(); treeSet.add("10"); // ... System.out.println("first_treeSet = " + treeSet.first()); System.out.println("last_treeSet = " + treeSet.last()); // ... } } ...

    Java集合类常用方法时间复杂度.docx

    - `contains()`:需要遍历整个ArrayList,时间复杂度为O(N)。 2. HashMap: - HashMap利用数组和链表(或红黑树)的数据结构,提供快速的增删查改操作,其时间复杂度通常为O(1)。 - `containsKey()`:直接通过...

    java _Tree.rar

    5. **操作与特性**:无论是`TreeSet`还是`TreeMap`,它们都提供了丰富的API,如`containsKey/containsValue`用于检查元素是否存在,`put/get/remove`用于添加、获取和移除元素,以及`firstKey/lastKey`用于获取最小...

    java集合类源码分析之Set详解.docx

    - `contains(Object o)`:判断集合是否包含指定元素,通过调用HashMap的`containsKey()`方法实现。 4. 删除元素: - `remove(Object o)`:删除指定元素,调用HashMap的`remove()`方法,返回值表示操作是否成功。 ...

    Java集合讲义大全.docx

    Collection 是 List 和 Set 的父接口,在 Collection 中定义了一些主要方法,例如 add、addAll、clear、contains、containsAll、equals、hashCode、isEmpty、iterator、remove、removeAll 和 retainAll 等。...

    【IT十八掌徐培成】Java基础第10天-05.set特点与操作.zip

    在Java中,Set接口有多个实现类,如HashSet、TreeSet等,它们各有各的特性。 首先,我们来聊聊HashSet。HashSet是最常用的Set实现类,它基于哈希表实现,因此插入和查找的平均时间复杂度为O(1)。然而,由于其内部...

    Collectionjs:SortedSet,SortedList,Queue,ArrayList,LinkedList,TreeSet,HashMap

    console.log("Contains k "+sets.contains("k")); for(var c in sets.toArray()) console.log(sets.get(c)); var list=new Collection.SortedList(); list.compare=function(a,b) { if(a.name&lt;b&gt;b.name) return

    Java-Java集合体系-List-Set

    Java集合体系是Java编程中非常核心的部分,涵盖了用于存储和操作数据的各种数据结构。在Java中,集合主要分为三大接口:List、...在面试中,深入理解集合的底层原理和操作性能,能展现出扎实的Java基础和问题解决能力。

    Java集合中的Set详解(带脑图)

    HashSet是基于HashMap实现的,提供了常数时间的性能特点,即add, remove, contains操作的时间复杂度都是O(1)。它通过元素的哈希码来确定元素在内部的存储位置,因此不支持元素的有序性。由于内部使用HashMap来存储...

    JAVA中软面试题

    对于选项A的`toString()`,它不会影响`contains()`方法的结果,因为`toString()`主要用于提供对象的字符串表示形式,而`contains()`并不依赖于对象的字符串表示。 选项B的`equals()`方法则至关重要,因为它直接决定...

    java.集合框架.md

    Java集合框架的并发集合类,如ConcurrentHashMap和CopyOnWriteArrayList等,是为了解决在多线程环境中使用集合时可能遇到的线程安全问题,提供了各自不同的线程安全实现方式。 在实际开发中,开发者需要根据具体...

    java中set接口使用方法详解

    Set接口的通用操作包括添加元素(`add()`)、删除元素(`remove()`)、检查元素是否存在(`contains()`)以及获取集合大小(`size()`)等。由于Set接口不保证元素的顺序,因此不适合那些依赖于元素特定顺序的应用场景。 在...

    10a_TreeSetPractice-2170592:10a_TreeSetPractice-2170592由GitHub Classroom创建

    - `contains()`方法检查集合是否包含特定元素,如`set.contains("element");` - `isEmpty()`检查集合是否为空。 6. **遍历元素** - 使用`iterator()`获取迭代器,然后通过迭代器逐个访问元素,例如: ```java ...

Global site tag (gtag.js) - Google Analytics