1. 程式人生 > >Java的TreeMap和HashMap的介紹和使用

Java的TreeMap和HashMap的介紹和使用

1. TreeMap的介紹和使用

第1部分 TreeMap介紹

TreeMap 簡介

TreeMap 是一個有序的key-value集合,它是通過紅黑樹實現的。
TreeMap 繼承於AbstractMap,所以它是一個Map,即一個key-value集合。
TreeMap 實現了NavigableMap介面,意味著它支援一系列的導航方法。比如返回有序的key集合。
TreeMap 實現了Cloneable介面,意味著它能被克隆
TreeMap 實現了java.io.Serializable介面,意味著它支援序列化

TreeMap基於紅黑樹(Red-Black tree)實現。該對映根據其鍵的自然順序進行排序

,或者根據建立對映時提供的 Comparator 進行排序,具體取決於使用的構造方法。
TreeMap的基本操作 containsKey、get、put 和 remove 的時間複雜度是 log(n) 。
另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。

TreeMap的建構函式
// 預設建構函式。使用該建構函式,TreeMap中的元素按照自然排序進行排列。  
TreeMap()  
  
// 建立的TreeMap包含Map  
TreeMap(Map<? extends K, ? extends V> copyFrom)  
  
// 指定Tree的比較器  
TreeMap(Comparator<? super K> comparator)  
  
// 建立的TreeSet包含copyFrom  
TreeMap(SortedMap<K, ? extends V> copyFrom) 

TreeMap的API

Map.Entry<K,V>    ceilingEntry(K key)   
         返回一個鍵-值對映關係,它與大於等於給定鍵的最小鍵關聯;如果不存在這樣的鍵,則返回 null。  
K   ceilingKey(K key)   
         返回大於等於給定鍵的最小鍵;如果不存在這樣的鍵,則返回 null。  
void    clear()   
         從此對映中移除所有對映關係。  
Object  clone()   
         返回此 TreeMap 例項的淺表副本。  
Comparator<? super K> comparator()   
         返回對此對映中的鍵進行排序的比較器;如果此對映使用鍵的自然順序,則返回 null。  
boolean containsKey(Object key)   
         如果此對映包含指定鍵的對映關係,則返回 true。  
boolean containsValue(Object value)   
         如果此對映為指定值對映一個或多個鍵,則返回 true。  
NavigableSet<K>   descendingKeySet()   
         返回此對映中所包含鍵的逆序 NavigableSet 檢視。  
NavigableMap<K,V> descendingMap()   
         返回此對映中所包含對映關係的逆序檢視。  
Set<Map.Entry<K,V>> entrySet()   
         返回此對映中包含的對映關係的 Set 檢視。  
Map.Entry<K,V>    firstEntry()   
         返回一個與此對映中的最小鍵關聯的鍵-值對映關係;如果對映為空,則返回 null。  
K   firstKey()   
         返回此對映中當前第一個(最低)鍵。  
Map.Entry<K,V>    floorEntry(K key)   
         返回一個鍵-值對映關係,它與小於等於給定鍵的最大鍵關聯;如果不存在這樣的鍵,則返回 null。  
K   floorKey(K key)   
         返回小於等於給定鍵的最大鍵;如果不存在這樣的鍵,則返回 null。  
V   get(Object key)   
         返回指定鍵所對映的值,如果對於該鍵而言,此對映不包含任何對映關係,則返回 null。  
SortedMap<K,V>    headMap(K toKey)   
         返回此對映的部分檢視,其鍵值嚴格小於 toKey。  
NavigableMap<K,V> headMap(K toKey, boolean inclusive)   
         返回此對映的部分檢視,其鍵小於(或等於,如果 inclusive 為 true)toKey。  
Map.Entry<K,V>    higherEntry(K key)   
         返回一個鍵-值對映關係,它與嚴格大於給定鍵的最小鍵關聯;如果不存在這樣的鍵,則返回 null。  
K   higherKey(K key)   
         返回嚴格大於給定鍵的最小鍵;如果不存在這樣的鍵,則返回 null。  
Set<K>    keySet()   
         返回此對映包含的鍵的 Set 檢視。  
Map.Entry<K,V>    lastEntry()   
         返回與此對映中的最大鍵關聯的鍵-值對映關係;如果對映為空,則返回 null。  
K   lastKey()   
         返回對映中當前最後一個(最高)鍵。  
Map.Entry<K,V>    lowerEntry(K key)   
         返回一個鍵-值對映關係,它與嚴格小於給定鍵的最大鍵關聯;如果不存在這樣的鍵,則返回 null。  
K   lowerKey(K key)   
         返回嚴格小於給定鍵的最大鍵;如果不存在這樣的鍵,則返回 null。  
NavigableSet<K>   navigableKeySet()   
         返回此對映中所包含鍵的 NavigableSet 檢視。  
Map.Entry<K,V>    pollFirstEntry()   
         移除並返回與此對映中的最小鍵關聯的鍵-值對映關係;如果對映為空,則返回 null。  
Map.Entry<K,V>    pollLastEntry()   
         移除並返回與此對映中的最大鍵關聯的鍵-值對映關係;如果對映為空,則返回 null。  
V   put(K key, V value)   
         將指定值與此對映中的指定鍵進行關聯。  
void    putAll(Map<? extends K,? extends V> map)   
         將指定對映中的所有對映關係複製到此對映中。  
V   remove(Object key)   
         如果此 TreeMap 中存在該鍵的對映關係,則將其刪除。  
int size()   
         返回此對映中的鍵-值對映關係數。  
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)   
         返回此對映的部分檢視,其鍵的範圍從 fromKey 到 toKey。  
SortedMap<K,V>    subMap(K fromKey, K toKey)   
         返回此對映的部分檢視,其鍵值的範圍從 fromKey(包括)到 toKey(不包括)。  
SortedMap<K,V>    tailMap(K fromKey)   
         返回此對映的部分檢視,其鍵大於等於 fromKey。  
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)   
         返回此對映的部分檢視,其鍵大於(或等於,如果 inclusive 為 true)fromKey。  
Collection<V> values()   
         返回此對映包含的值的 Collection 檢視。  

第2部分 TreeMap資料結構

TreeMap的繼承關係

java.lang.Object
	java.util.AbstractMap<K, V>
		java.util.TreeMap<K, V>
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable {}

TreeMap與Map關係如下圖:

從圖中可以看出:
(01) TreeMap實現繼承於AbstractMap,並且實現了NavigableMap介面。
(02) TreeMap的本質是R-B Tree(紅黑樹),它包含幾個重要的成員變數: rootsizecomparator
  root 是紅黑數的根節點。它是Entry型別,Entry是紅黑數的節點,它包含了紅黑數的6個基本組成成分:key(鍵)、value(值)、left(左孩子)、right(右孩子)、parent(父節點)、color(顏色)。Entry節點根據key進行排序,Entry節點包含的內容為value。 
  紅黑數排序時,根據Entry中的key進行排序;Entry中的key比較大小是根據比較器comparator來進行判斷的。
  size是紅黑數中節點的個數。


第3部分 TreeMap遍歷方式

3.1 遍歷TreeMap的鍵值對

第一步:根據entrySet()獲取TreeMap的“鍵值對”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設map是TreeMap物件  
// map中的key是String型別,value是Integer型別  
Integer integ = null;  
Iterator iter = map.entrySet().iterator();  
while(iter.hasNext()) {  
    Map.Entry entry = (Map.Entry)iter.next();  
    // 獲取key  
    key = (String)entry.getKey();  
        // 獲取value  
    integ = (Integer)entry.getValue();  
}

3.2 遍歷TreeMap的鍵

第一步:根據keySet()獲取TreeMap的“鍵”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設map是TreeMap物件  
// map中的key是String型別,value是Integer型別  
String key = null;  
Integer integ = null;  
Iterator iter = map.keySet().iterator();  
while (iter.hasNext()) {  
        // 獲取key  
    key = (String)iter.next();  
        // 根據key,獲取value  
    integ = (Integer)map.get(key);  
}  

3.3 遍歷TreeMap的值

第一步:根據value()獲取TreeMap的“值”的集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設map是TreeMap物件  
// map中的key是String型別,value是Integer型別  
Integer value = null;  
Collection c = map.values();  
Iterator iter= c.iterator();  
while (iter.hasNext()) {  
    value = (Integer)iter.next();  
}

2. HashMap的介紹和使用

HashMap簡介 
HashMap 是一個散列表,它儲存的內容是鍵值對(key-value)對映。 
HashMap 繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable介面。 
HashMap 的實現不是同步的,這意味著它不是執行緒安全的。它的key、value都可以為null。此外,HashMap中的對映不是有序的。 
HashMap 的例項有兩個引數影響其效能:“初始容量” 和 “載入因子”。容量 是雜湊表中桶的數量,初始容量 只是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行 rehash 操作(即重建內部資料結構),從而雜湊表將具有大約兩倍的桶數。 
通常,預設載入因子是 0.75, 這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設定初始容量時應該考慮到對映中所需的條目數及其載入因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以載入因子,則不會發生 rehash 操作。

HashMap的繼承關係 

HashMap與Map關係如下圖: 
 
HashMap的建構函式 
HashMap共有4個建構函式,如下:

複製程式碼 程式碼如下:

// 預設建構函式。 
HashMap() 
// 指定“容量大小”的建構函式 
HashMap(int capacity) 
// 指定“容量大小”和“載入因子”的建構函式 
HashMap(int capacity, float loadFactor) 
// 包含“子Map”的建構函式 
HashMap(Map<? extends K, ? extends V> map)

HashMap的API

複製程式碼 程式碼如下:

void                 clear() 
Object               clone() 
boolean              containsKey(Object key) 
boolean              containsValue(Object value) 
Set<Entry<K, V>>     entrySet() 
V                    get(Object key) 
boolean              isEmpty() 
Set<K>               keySet() 
V                    put(K key, V value) 
void                 putAll(Map<? extends K, ? extends V> map) 
V                    remove(Object key) 
int                  size() 
Collection<V>        values()

3. HashMap,LinkedHashMap,TreeMap的有序性

HashMap 是將 Key 做 Hash 演算法,然後將 Hash 值對映到記憶體地址,直接取得 Key 所對應的資料。在 HashMap 中,底層資料結構使用的是陣列,所謂的記憶體地址即陣列的下標索引。HashMap 的高效能需要保證以下幾點:


Hash 演算法必須是高效的;
Hash 值到記憶體地址 (陣列索引) 的演算法是快速的;
根據記憶體地址 (陣列索引) 可以直接取得對應的值。
HashMap 實際上是一個連結串列的陣列。基於 HashMap 的連結串列方式實現機制,只要 HashCode() 和 Hash() 方法實現得足夠好,能夠儘可能地減少衝突的產生,那麼對 HashMap 的操作幾乎等價於對陣列的隨機訪問操作,具有很好的效能。但是,如果 HashCode() 或者 Hash() 方法實現較差,在大量衝突產生的情況下,HashMap 事實上就退化為幾個連結串列,對 HashMap 的操作等價於遍歷連結串列,此時效能很差。


HashMap 的一個功能缺點是它的無序性,被存入到 HashMap 中的元素,在遍歷 HashMap 時,其輸出是無序的。如果希望元素保持輸入的順序,可以使用 LinkedHashMap 替代。


LinkedHashMap 繼承自 HashMap,具有高效性,同時在 HashMap 的基礎上,又在內部增加了一個連結串列,用以存放元素的順序。


HashMap 通過 hash 演算法可以最快速地進行 Put() 和 Get() 操作。TreeMap 則提供了一種完全不同的 Map 實現。從功能上講,TreeMap 有著比 HashMap 更為強大的功能,它實現了 SortedMap 介面,這意味著它可以對元素進行排序。TreeMap 的效能略微低於 HashMap。如果在開發中需要對元素進行排序,那麼使用 HashMap 便無法實現這種功能,使用 TreeMap 的迭代輸出將會以元素順序進行。LinkedHashMap 是基於元素進入集合的順序或者被訪問的先後順序排序,TreeMap 則是基於元素的固有順序 (由 Comparator 或者 Comparable 確定)。


LinkedHashMap 是根據元素增加或者訪問的先後順序進行排序,而 TreeMap 則根據元素的 Key 進行排序。

測試程式碼:

package mapKeySet;  
  
import java.util.HashMap;  
import java.util.LinkedHashMap;  
import java.util.Map;  
import java.util.TreeMap;  
  
/** 
 * 2015年4月9日下午3:33:44 
 * @version 1.0 
 */  
public class KeySetTest {  
    public static void main(String[] args) {  
        Map<String, String> map = new HashMap<String, String>();  
        map.put("a", "1");  
        map.put("b", "2");  
        map.put("c", "3");  
        map.put("d", "4");  
          
        System.out.print("HashMap:");  
        for(String key : map.keySet()) {  
            System.out.print(map.get(key) + " ");  
        }  
          
        Map<String, String> linkedMap = new LinkedHashMap<String, String>();  
        linkedMap.put("a", "1");  
        linkedMap.put("b", "2");  
        linkedMap.put("c", "3");  
        linkedMap.put("d", "4");  
          
        System.out.print("LinkedHashMap:");  
        for(String key : linkedMap.keySet()) {  
            System.out.print(linkedMap.get(key) + " ");  
        }  
          
        Map<String, String> treeMap = new TreeMap<String, String>();  
        treeMap.put("a", "1");  
        treeMap.put("b", "2");  
        treeMap.put("c", "3");  
        treeMap.put("d", "4");  
          
        System.out.print("TreeMap:");  
        for(String key : treeMap.keySet()) {  
            System.out.print(treeMap.get(key) + " ");  
        }  
    }  
}

輸出結果:

HashMap:4 2 3 1 LinkedHashMap:1 2 3 4 TreeMap:1 2 3 4

4. 二維HashMap

宣告:

HashMap<String,HashMap<String,Integer>> map1;

新增元素:

HashMap<String,Integer> temp_hash=new HashMap<String,Integer>();  
temp_hash.put(string1, 1);  
map1.put(string2,temp_hash);

遍歷:

申請一個迭代器:

Iterator<String> it1=map1.keySet().iterator();

訪問:

while(it_verb.hasNext()){  
   String temp=it.next();  
   HashMap<String,Integer> temp_map=verb_map.get(temp);  
}  
// 程式碼實現
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

public class TestTreeMap {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeMap<Integer, String> map = new TreeMap<>();
		map.put(3, "aa");
		map.put(2, "bb");
		map.put(4, "cc");
		map.put(1, "dd");
		map.put(5, "dd");
		map.put(6, "ee");
		System.out.print("original: ");
		Iterator it = map.entrySet().iterator();
		while(it.hasNext()) {
			Map.Entry e = (Map.Entry)it.next();
			int key = (Integer)e.getKey();
			String val = (String)e.getValue();
			System.out.print(key + " " + val + (it.hasNext() ? ", " : "."));
		}
		System.out.println();
		System.out.println("-------------------------------");
		map.remove(6);
		System.out.print("after remove: ");
		it = map.entrySet().iterator();
		while(it.hasNext()) {
			Map.Entry e = (Map.Entry)it.next();
			int key = (Integer)e.getKey();
			String val = (String)e.getValue();
			System.out.print(key + " " + val + (it.hasNext() ? ", " : "."));
		}
		System.out.println();
		System.out.println("-------------------------------");
		System.out.println(3 + "'s val: " + map.get(3));
		System.out.println(3 + "'s higherKey: " + map.higherKey(3));
		Map.Entry tmp1 = map.higherEntry(3);
		System.out.println(3 + "'s higherEntry: " + (Integer)tmp1.getKey() + " " + (String)tmp1.getValue());

		System.out.println(3 + "'s lowerKey: " + map.lowerKey(3));
		Map.Entry tmp2 = map.lowerEntry(3);
		System.out.println(3 + "'s lowerEntry: " + (Integer)tmp2.getKey() + " " + (String)tmp2.getValue());
		
		System.out.println("firstKey: " + map.firstKey() + ", " + "lastKey: " + map.lastKey());
		System.out.println();
		
		TestUserDefined();
		
		TestTwoDimensional();
		
	}
	
	private static class Node implements Comparable<Node> {
		int a, b;
		public Node(int a, int b) {
			this.a = a;
			this.b = b;
		}
		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			if(this.a == o.a) {
				return (this.b < o.b) ? 1 : -1;
			}
			else {
				return (this.a > o.a) ? 1 : -1;
			}
		}
		public String toString() {
			return "{ " + this.a + "," + this.b + " }";
		}
	}
	
	private static class mycmp implements Comparator<Node> {

		@Override
		public int compare(Node o1, Node o2) {
			// TODO Auto-generated method stub
			if(o1.a == o2.a) {
				return o1.b - o2.b;
			}
			return o2.a - o1.a;
		}
		
	}
	
	private static void TestUserDefined() {
		// By Comparable介面
		TreeMap<Node, String> map1 = new TreeMap<>();
		map1.put(new Node(3, 2), "aa");
		map1.put(new Node(3, 4), "bb");
		map1.put(new Node(5, 8), "cc");
		map1.put(new Node(5, 7), "dd");
		map1.put(new Node(6, 9), "ee");
		Iterator it1 = map1.entrySet().iterator();
		while(it1.hasNext()) {
			Map.Entry e = (Map.Entry)it1.next();
			System.out.println((Node)e.getKey() + ": " + (String)e.getValue());
		}
		
		System.out.println();
		System.out.println("-------------------------------");
		System.out.println();
		
		// By Comparator介面
		TreeMap<Node, String> map2 = new TreeMap<>(new mycmp());
		map2.put(new Node(3, 2), "aa");
		map2.put(new Node(3, 4), "bb");
		map2.put(new Node(5, 8), "cc");
		map2.put(new Node(5, 7), "dd");
		map2.put(new Node(6, 9), "ee");
		Iterator it2 = map2.entrySet().iterator();
		while(it2.hasNext()) {
			Map.Entry e = (Map.Entry)it2.next();
			System.out.println((Node)e.getKey() + ": " + (String)e.getValue());
		}
		System.out.println();
	}
	
	private static void TestTwoDimensional() {
		TreeMap<Integer, TreeMap<Integer, String>> mmp = new TreeMap<>();
		TreeMap<Integer, String> tmpMap = new TreeMap<>();
		tmpMap.put(1, "a");
		tmpMap.put(3, "b");
		tmpMap.put(2, "c");
		mmp.put(1, tmpMap);
		mmp.put(3, tmpMap);
		mmp.put(2, tmpMap);
		Iterator it = mmp.entrySet().iterator();
		while(it.hasNext()) {
			Map.Entry e = (Map.Entry)it.next();
			int key = (Integer)e.getKey();
			tmpMap = (TreeMap<Integer, String>)e.getValue();
			System.out.print(key + "-> { ");
			
			Iterator tmpIt = tmpMap.entrySet().iterator();
			while(tmpIt.hasNext()) {
				Map.Entry tmpe = (Map.Entry)tmpIt.next();
				int tmpkey = (Integer)tmpe.getKey();
				String tmpval = (String)tmpe.getValue();
				System.out.print(tmpkey + " " + tmpval + (tmpIt.hasNext() ? ", " : ""));
			}
			System.out.println(" }");
		}
	}
	
}

繼續加油~