现在的位置: 首页 > 综合 > 正文

读JSE源码(三)集合之TreeMap(1)

2018年11月07日 ⁄ 综合 ⁄ 共 4545字 ⁄ 字号 评论关闭

1 TreeMap介绍

TreeMap是基于红黑树(red black tree)算法和NavigableMap实现的。

注意,此实现不是同步的。如果多个线程同时访问一个映射,并且其中至少一个线程从结构上修改了该映射,则其必须 外部同步。(结构上的修改是指添加或删除一个或多个映射关系的操作;仅改变与现有键关联的值不是结构上的修改。)这一般是通过对自然封装该映射的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSortedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示:

   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));


TreeMap是泛型类,K代表key(键)的类型,V代表value(值)的类型,它继承了类AbstractMap,实现了接口:

SerializableCloneableMap<K,V>, NavigableMap<K,V>, SortedMap<K,V>

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
    /**
     * The comparator used to maintain order in this tree map, or
     * null if it uses the natural ordering of its keys.
     *
     * @serial
     */
    private final Comparator<? super K> comparator;

    private transient Entry<K,V> root = null;

    /**
     * The number of entries in the tree
     */
    private transient int size = 0;

    /**
     * The number of structural modifications to the tree.
     */
    private transient int modCount = 0;

它的3个构造函数如下:

(1)使用这个构造函数,因为comparator为null,但是TreeMap会按照key来排序,所以key对象要实现Comparable接口

    public TreeMap() {
        comparator = null;
    }


(2)这个构造函数会传入一个实现了Comparator接口的比较器对象,所以key对象自己不需要实现Comparable接口,key会按照传入的比较器对象进行排序

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

(3)相当于将传入的Map复制给了当前的TreeMap

Constructs a new tree map containing the same mappings and using the same ordering as the specified sorted map. This method runs in linear time.

传入的Map的key对象要实现Comparable接口

    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }


总结:TreeMap是按照key进行排序,所以key对象要实现Comparable接口或者根据构造函数传入实现了Comaprator接口的对象。

Comparble和Comparator使用见读JDK源码(二):Comparable接口和Comparator接口

2 TreeMap使用(增删查改)

下面从增删查改角度介绍TreeMap的使用,直接看代码:

package zyang.map;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/** 
 * @author  secret
 * @version 1.0
 * @date    2012-11-30 上午10:00:05 
 * @fuction TreeMap的使用(增删查改)
 */

public class TreeMapTest {
	
    //print
	public static void printElements(Collection c)
	{
		Iterator it =c.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next());
		}
	} //printElements(Collection c)
	

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Map tm=new TreeMap();
		
		//1 插入元素
		tm.put("shanghai", new Student(0, "shanghai"));
		tm.put("beijing", new Student(1, "beijing"));
		tm.put("上海", new Student(0, "上海"));
		tm.put("北京", new Student(1, "北京"));
				
		//2 删除(根据key值删除)
		//tm.remove("lisi");
		
		//3 修改(根据key值修改)
		//tm.put("zhangsan", new Student(0, "lisi"));
		
		//------------------4 查找元素-------------------------------
//		//根据key值得到元素
//		Student s=(Student)tm.get("wangwu");
//        
//		//key的所有值
//		Set keys=tm.keySet(); 
//		printElements(keys);  
//		
//		//value的所有值
//		Collection values=tm.values();
//		printElements(keys);  
		
		//4.1 查找元素方法一(跟据key值查找元素)
		Set keys=tm.keySet();
		//printElements(keys);
		Iterator it=keys.iterator();
		while(it.hasNext())
		{
			String key=(String)it.next();
			Student value=(Student)tm.get(key);
			System.out.println("key="+key+",student="+value);
		}
		
//		//4.2 查找元素方法二(根据Entry类型[Entry是键值对(键和值)]查找)
//		Set entry=tm.entrySet();
//		//printElements(entry);   //打印出来是类似这样的结果:key1=value1 key2=value2
//		Iterator entryIt=entry.iterator();
//		while(entryIt.hasNext())
//		{
//			Map.Entry me=(Map.Entry)it.next();
//			String key=(String)me.getKey();
//			Student value=(Student)me.getValue();	
//		}
	}

}

Student类如下:

public class Student {
	
	//学号
	int num;
	//姓名
	String name;
	
	//constructor
	public  Student (int num,String name)
	{
		this.num=num;
		this.name=name;
	}

	@Override
	public String toString() {
		return "Student [num=" + num + ", name=" + name + "]";
	}
}

输出结果如下:

key=beijing,student=Student [num=1, name=beijing]
key=shanghai,student=Student [num=0, name=shanghai]
key=上海,student=Student [num=0, name=上海]
key=北京,student=Student [num=1, name=北京]

3 TreeMap中文排序

上述输出结果中key的排序如下:

beijing shanghai 上海 北京

英文排序正确,但是中文排序则明显的不正确,北京应该在上海之前。上述排序key因为是字符串(而字符串默认实现了Comparble接口)。这个主要是java中使用中文编码GB2312或者JBK时,char型转换成int型得过程出现了比较大的偏差。Java中之所以出现偏差,主要是compare方法的问题,所以这里自己实现Comparator接口,而国际化的问题,使用Collator类来解决。代码如下:

package zyang.map;

import java.text.CollationKey;
import java.text.Collator;
import java.util.Comparator;

/** 
 * @author  yangzhong  E-mail:yangzhonglive@gmail.com
 * @version 1.0
 * @date    2012-11-30 下午3:36:52 
 * @fuction 
 */

public class ChineseComparator implements Comparator
{
    Collator collator=Collator.getInstance();
	
	public int compare(Object o1, Object o2) {
		CollationKey key1=collator.getCollationKey(o1.toString());
		CollationKey key2=collator.getCollationKey(o2.toString());
		
		return  key1.compareTo(key2);
	}

}

修改TreeMapTest中找到创建TreeMap的构造函数

Map tm=new TreeMap();

需要修改为

Comparator chineseComparator=new  ChineseComparator();

Map tm=new TreeMap(chineseComparator);
再次运行TreeMapTest结果如下:

key=beijing,student=Student [num=1, name=beijing]
key=shanghai,student=Student [num=0, name=shanghai]
key=北京,student=Student [num=1, name=北京]
key=上海,student=Student [num=0, name=上海]

可以看到中文排序正确了

4 读源码(链接)

这篇文章分析的不错:

通过分析 JDK 源代码研究 TreeMap 红黑树算法实现


抱歉!评论已关闭.