HashMap与TreeMap的区别

来源:互联网 发布:linux下gdb调试输出 编辑:程序博客网 时间:2024/05/29 14:02
图灵赠书——程序员11月书单    【思考】Python这么厉害的原因竟然是!    感恩节赠书:《深度学习》等异步社区优秀图书和作译者评选启动!    每周荐书:京东架构、Linux内核、Python全栈
window.quickReplyflag = true; var isBole = false; var fasrc="http://my.csdn.net/my/favorite/miniadd?t=HashMap%e5%92%8cTreeMap%e5%8c%ba%e5%88%ab%e8%af%a6%e8%a7%a3%e4%bb%a5%e5%8f%8a%e5%ba%95%e5%b1%82%e5%ae%9e%e7%8e%b0&u=http://blog.csdn.net/xlgen157387/article/details/47907721"

HashMap和TreeMap区别详解以及底层实现

    <div class="article_manage clearfix">    <div class="article_l">        <span class="link_categories">        标签:          <a href="http://www.csdn.net/tag/hashmap" target="_blank" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">hashmap</a><a href="http://www.csdn.net/tag/treemap" target="_blank" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">treemap</a>        </span>    </div>    <div class="article_r">        <span class="link_postdate">2015-08-23 18:23</span>        <span class="link_view" title="阅读次数">7286人阅读</span>        <span class="link_comments" title="评论次数"> <a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(2)</span>        <span class="link_collect tracking-ad" data-mod="popu_171"> <a href="javascript:void(0);" onclick="javascript:collectArticle('HashMap%e5%92%8cTreeMap%e5%8c%ba%e5%88%ab%e8%af%a6%e8%a7%a3%e4%bb%a5%e5%8f%8a%e5%ba%95%e5%b1%82%e5%ae%9e%e7%8e%b0','47907721');return false;" title="收藏" target="_blank">收藏</a></span>         <span class="link_report"> <a href="#report" onclick="javascript:report(47907721,2);return false;" title="举报">举报</a></span>    </div></div>    <style type="text/css">                .embody{            padding:10px 10px 10px;            margin:0 -20px;            border-bottom:solid 1px #ededed;                        }        .embody_b{            margin:0 ;            padding:10px 0;        }        .embody .embody_t,.embody .embody_c{            display: inline-block;            margin-right:10px;        }        .embody_t{            font-size: 12px;            color:#999;        }        .embody_c{            font-size: 12px;        }        .embody_c img,.embody_c em{            display: inline-block;            vertical-align: middle;                       }         .embody_c img{                           width:30px;            height:30px;        }        .embody_c em{            margin: 0 20px 0 10px;            color:#333;            font-style: normal;        }</style><script type="text/javascript">    $(function () {        try        {            var lib = eval("("+$("#lib").attr("value")+")");            var html = "";            if (lib.err == 0) {                $.each(lib.data, function (i) {                    var obj = lib.data[i];                    //html += '<img src="' + obj.logo + '"/>' + obj.name + "&nbsp;&nbsp;";                    html += ' <a href="' + obj.url + '" target="_blank">';                    html += ' <img src="' + obj.logo + '">';                    html += ' <em><b>' + obj.name + '</b></em>';                    html += ' </a>';                });                if (html != "") {                    setTimeout(function () {                        $("#lib").html(html);                                              $("#embody").show();                    }, 100);                }            }              } catch (err)        { }    });</script>  <div class="category clearfix">    <div class="category_l">       <img src="http://static.blog.csdn.net/images/category_icon.jpg">        <span>分类:</span>    </div>    <div class="category_r">                <label onclick="GetCategoryArticles('2145319','u010870518','top','47907721');">                    <span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">Java技术提高<em>(61)</em></span>                  <img class="arrow-down" src="http://static.blog.csdn.net/images/arrow_triangle _down.jpg" style="display:inline;">                  <img class="arrow-up" src="http://static.blog.csdn.net/images/arrow_triangle_up.jpg" style="display:none;">                    <div class="subItem">                        <div class="subItem_t"><a href="http://blog.csdn.net/u010870518/article/category/2145319" target="_blank">作者同类文章</a><i class="J_close">X</i></div>                        <ul class="subItem_l" id="top_2145319">                                                    </ul>                    </div>                </label>                        </div></div>    <div class="bog_copyright">                 <p class="copyright_p">版权声明:本文为博主原创文章,未经博主允许不得转载。</p>    </div>

目录(?)[+]

  1. 前言
  2. HashMap 代码分析
  3. TreeMap代码分析
  4. HashMap和TreeMap比较

前言

首先介绍一下什么是Map.在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.这就是我们平时说的键值对。

HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。

HashMap 代码分析

HashMap 是基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。


官方文档如下:
此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

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

Map m = Collections.synchronizedMap(new HashMap(…));
由所有此类的“collection 视图方法”所返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。


Map.put()的时候,需要将key值映射为相应的hash值,key的值是以char数组的形式存放的,value对应的值也是有char数组存放的

这里写图片描述

这里写图片描述

在进行存放的时候,首先检查table是否为空,如果为空使用inflateTable方法进行初始化操作。

这里用到的hash方法如下:
这里写图片描述

Map.get()的时候,是根据hash值进行查找的:
这里写图片描述

这里写图片描述

然后就是调用hash方法,找到具体的key所对应的hash,然后再到entry中去找value

TreeMap代码分析

这里写图片描述

看到上边,可知TreeMap并不是基于hash实现的,据说是红黑树,红黑树这块几乎空白,不敢多说:

TreeMap:基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
  (1)TreeMap():构建一个空的映像树
  (2)TreeMap(Map m): 构建一个映像树,并且添加映像m中所有元素
  (3)TreeMap(Comparator c): 构建一个映像树,并且使用特定的比较器对关键字进行排序
  (4)TreeMap(SortedMap s): 构建一个映像树,添加映像树s中所有映射,并且使用与有序映像s相同的比较器排序。


官方文档:
基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

此实现为 containsKey、get、put 和 remove 操作提供受保证的 log(n) 时间开销。这些算法是 Cormen、Leiserson 和 Rivest 的 Introduction to Algorithms 中的算法的改编。

注意,如果要正确实现 Map 接口,则有序映射所保持的顺序(无论是否明确提供了比较器)都必须与 equals 一致。(关于与 equals 一致 的精确定义,请参阅 Comparable 或 Comparator)。这是因为 Map 接口是按照 equals 操作定义的,但有序映射使用它的 compareTo(或 compare)方法对所有键进行比较,因此从有序映射的观点来看,此方法认为相等的两个键就是相等的。即使排序与 equals 不一致,有序映射的行为仍然是 定义良好的,只不过没有遵守 Map 接口的常规协定。

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

SortedMap m = Collections.synchronizedSortedMap(new TreeMap(…));
collection(由此类所有的“collection 视图方法”返回)的 iterator 方法返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器自身的 remove 方法,否则在其他任何时间以任何方式进行修改都将导致迭代器抛出 ConcurrentModificationException。因此,对于并发的修改,迭代器很快就完全失败,而不会冒着在将来不确定的时间发生不确定行为的风险。


HashMap和TreeMap比较

(1)HashMap:适用于在Map中插入、删除和定位元素。
(2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
(3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.
(4)HashMap 非线程安全 TreeMap 非线程安全
(5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。

 在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。

(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;varnumbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append(numbering); for (i = 1; i
原创粉丝点击