红黑树

HashMap底层数据结构详解

梦想与她 提交于 2019-12-01 07:17:04
一、HashMap底层数据结构 JDK1.7及之前:数组+链表 JDK1.8:数组+链表+红黑树 关于HashMap基本的大家都知道,但是为什么数组的长度必须是2的指数次幂,为什么HashMap的加载因子要设置为0.75,为什么链表长度大于等于8时转成了红黑树? HashMap添加元素分析 当添加元素时,会通过哈希值和数组长度计算计算下标来准确定位该元素应该put的位置,通常我们为了使元素时分布均匀会使用取模运算,用一个值去模上总长度,例如: index=hashCode % arr.length (实际并非这样,后面讲解),计算出index后,就会将该元素添加进去,理想状态下是将每个值都均匀的添加到数组中,但问题是不可能达到这样的理想状态,这时候就会产生哈希冲突,例如:小龙女通过计算添加到了数组3号位置,但是此时杨过这个元素通过计算产生了一个与小龙女相同的索引位置,这是就产生了哈希冲突 此时,就产生了第二种数据结构——链表,冲突的元素会在该索引处以链表的形式保存 但是当链表的长度过长时,其固有弊端就显现出来了,即查询效率较低,时间复杂度可能会达到O(n)级别,而数组的查询时间复杂度仅为O(1) 此时,就引出了第三种数据结构——红黑树,红黑树是一棵接近于平衡的二叉树,其查询时间复杂度为O(logn),远远比链表的查询效率高。但如果链表长度不到一定的阈值

TreeMap的源码学习

◇◆丶佛笑我妖孽 提交于 2019-12-01 05:36:16
TreeMap的源码学习 一)、TreeMap的特点 根据key值进行排序。 二)、按key值排序的两种排序算法实现 1).在构造方法中传入比较器 public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } 比较器comparator实现Comparator接口,实现compare(T o1, T o2)方法; int compare(T o1, T o2); 2).key值实现Comparable接口,重写 compareTo(key k)方法 T implements Comparable<T>{ @override public int compareTo(T k) } 注: 对于TreeMap而言,排序是一个必须进行的过程,要正常使用TreeMap必须制 定排序规则,加入Comparator或key对象实现Comparable接口,若没有制定 比较规则则会抛出java.lang.ClassCastException。 因为String对象默认实现了Comparable接口,实现了comparaTo方法,使用String类型作为key值,不用进行排序。 三)、TreeMap的数据结构 红黑树:Entry<k, v> Entry<k ,v> 对象的属性: K key; V

hashMap 1.8.0_91 浅析

你说的曾经没有我的故事 提交于 2019-12-01 02:25:41
我对红黑树不是很了解,所以解说不是很好。还有remove等方法没写,以后再说。linkedHashMap,treeMap,也在说 hashMap由数组、链表、红黑树组成。 why? 数组,查找快!只要知道下标,Array[index]就查到了,但是向指定下标插入一个值,当该位置有值(我称之为原值)时,则要考虑原值的去留问题! 链表,插入、删除快!只要更改prev、next的指向即可,但是,查找慢,得一个个遍历! 红黑树,插入、查找、删除都快!但是比较复杂。后面有时间,我会慢慢搞透他! 如下图所示: 图一 hashMap基础数据结构 1. 概述 hashMap由 transient Node<K,V>[] table (这就是数组) 组成。Node包含键值等属性 /** * 基本的桶节点,大多数实体都会用到:存储的<key,value>对应Node的key,value * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) */ static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key;

SGI-STL简记(七)-关联容器(set、map、multiset、multimap)

偶尔善良 提交于 2019-12-01 02:04:46
stl_set.h : set:有序关联容器,值类型和键类型为同一个,且各个容器元素唯一,插入或删除在线性时间内完成,此外插入等操作不会影响迭代器失效的情况; set:关联容器set模板类,其参数分别为_Key、_Compare、_Alloc,对应键值类型、比较函数、内存分配器; 此外提供了特化版本,其比较函数使用的是less<_Key>,分配器使用宏__STL_DEFAULT_ALLOCATOR作为默认分配器;可通过调整宏设置,故而可使用allocator< T >或alloc(malloc_alloc(即__malloc_alloc_template<0>) 或__default_alloc_template<__NODE_ALLOCATOR_THREADS, 0>)作为默认的内存分配器; 内部底层使用一个数据成员_M_t,其类型为RB_Tree红黑树结构来实现set,RB_Tree不仅被用于set,还被用于map、multiset、multimap的底层实现; set内部重声明类型key_type、value_type、key_compare、value_compare,其中key_type、value_type相同均为_Key,key_compare、value_compare则均为_Compare; 此外还有其他如指针、迭代器、引用、以及其他常规的声明类型;

day18

假如想象 提交于 2019-11-30 22:39:26
一、增加一个接口:java.lang.Iterable接口 JDK1.5增加 它有一个抽象方法:Iterator iterator() 实现这个接口允许对象成为 "foreach" 语句的目标 Collection从JDK1.5之后开始继承Iterable接口。 二、java.util.Iterator接口在哪里实现的? //左边是Iterator接口,说明右边一定创建了一个Iterator接口的实现类对象,否则iterator调用方法是没有方法体可以执行 Iterator iterator = list.iterator(); 跟踪源代码:list.iterator() public Iterator<E> iterator() { return new Itr();//Itr是一个内部类 } 跟踪每一种Collection的集合发现,所有的集合在内部都一个内部类来实现java.util.Iterator接口。 为什么? (1)每一种集合的内部实现物理结构不一样,有的是数组有的是链表等,迭代方式不一样,无法给出统一的实现 (2)迭代的作用,为某个集合迭代,遍历元素,那么它只为某类集合服务,迭代时又需要访问集合的内部(private)的元素, 所以我们设计为内部类更合适。 Set:是Collection另一个子接口 一个不包含重复元素的 collection。 更确切地讲,set

【C++】STL各容器的实现,时间复杂度,适用情况分析

北战南征 提交于 2019-11-30 19:03:47
一.vector 1.概述 动态数组,在内存中具有连续的储存空间,在堆上分配内存,支持快速随机访问,在中间插入和删除慢,但在末尾插入和删除快 2.特点 1)拥有一段连续的内存空间,并且起始地址不变,因此 能非常好的支持随机存取 ,但由于其内存空间是连续的,所以 在中间插入和删除会造成内存块的拷贝 ,另外,当该数组的内存空间不够时, 需要重新申请一块足够大的内存并进行内存拷贝 ,这些都大大的影响了vector的效率 2) 对头部和中间的元素进行插入删除需要移动内存 ,如果元素是结构体或者类,那么移动时还会进行 析构和构造 操作,所以性能不高 3) 对末尾的元素的操作最快 ,此时一般不需要移动内存,只有剩余内存不够时才需要 3.时间复杂度分析: 头部插入删除:O(N) 尾部插入删除:O(1) 中间插入删除:O(N) 查找:O(N) 4.优缺点及适用场景 优点:支持随机储存,查询效率高 缺点:在头部和中间插入删除元素效率低,需要移动内存 适用场景:适用于元素结构简单,变化小,并且频繁随机访问的场景 5.结论 vector常用来保存需要经常进行随机访问的内容,并且不需要对中间元素进行添加和删除操作 二.双向队列deque 1.概述 deque是 double ended queue 的缩写,是一个动态数组,可以向两端发展(双向开口的连续线性空间),因此无论在头部或者尾部安插元素都十分迅速

ConcurrentHashMap

◇◆丶佛笑我妖孽 提交于 2019-11-30 16:20:29
一、引入背景(Why) 1. 在多线程环境下,HashMap的put会导致扩容,扩容引起死循环,导致CPU使用率100% 2. 可以使用HashTable和Collections.synchronizedMap(hashMap)可以解决多线程的问题 3. HashTable和Collections.synchronizedMap(hashMap)对读写进行加一个 全局锁 ,一个线程读写map的元素,其余线程必须等待,性能不好 4. ConcurrentHashMap也加了锁,但是只锁了map的一部分,其余线程可以继续读写没锁住的部分,优化了操作性能 二、JDK1.7的实现(了解):Segment分段锁+HashEntry+ReentrantLock 1. HashEntry是键值对,用来存储数据 2. 桶是由若干个HashEntry连接起来的链表 3. Segment分段锁继承ReentrantLock,每个Segment对象锁住若干个桶 4. 一个ConcurrentHashMap实例中,包含由若干个Segment对象组成的数组 5. HashEntry->HashBucket->Segment->ConcurrentHashMap,一层一层被包含 三、JDK1.8的实现(理解):Node+CAS+Synchronized,锁的粒度更小 1. 数据结构

HashMap实现原理

ぐ巨炮叔叔 提交于 2019-11-30 16:15:52
1.基础信息 HashMap 底层是基于数组和链表实现的,容量的默认大小是 16,负载因子是 0.75。 2.基本原理 HashMap是基于散列法(又称哈希法hashing)的原理,使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket(桶)位置来储存Entry对象。”HashMap是在bucket中储存键对象和值对象,作为Map.Entry。并不是仅仅只在bucket中存储值。 put键值对的方法的过程是: 1)判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; 2)根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; 3)判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; 4)判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; 5)遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树

HashMap JDK1.8源码分析

别说谁变了你拦得住时间么 提交于 2019-11-30 03:15:37
HashMap JDK1.8和JDK1.7差异比较大。JDK1.8 HashMap采用数组+链表+红黑树存储值。 一、原理 当链表长度大于或者等于8时,链表转化为红黑树。 二、红黑树简单介绍。 https://www.cnblogs.com/nullllun/p/8214599.html 来源: https://www.cnblogs.com/laolei11/p/11535476.html

红黑树

ε祈祈猫儿з 提交于 2019-11-30 02:33:59
红黑树 红黑树(Red Black Tree) 是一种自平衡二叉查找树 红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。 二叉平衡树的严格平衡策略以牺牲建立查找结构(插入,删除操作)的代价,换来了稳定的O(logN) 的查找时间复杂度 它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。 特点: (1) 每个节点或者是黑色,或者是红色。 (2) 根节点是黑色。 (3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!] (4) 如果一个节点是红色的,则它的子节点必须是黑色的。 (5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。 插入节点的关键是: 插入新节点总是红色节点 如果插入节点的父节点是黑色, 能维持性质 如果插入节点的父节点是红色, 破坏了性质. 故插入算法就是通过重新着色或旋转, 来维持性质 红黑树和平衡二叉树主要区别: (1)对于搜索操作来说, AVL树是严格均衡树,其 搜索性能 要好于红黑树 (2)对于 插入和删除操作来说,红黑树的性能更好,它的旋转次数更少 ,因为不需要维持严格的平衡。 红黑树的实现: public class RBTree<K extends