1,概述

2,Collection

2.1,Set【接触比较少】

2.1.1 TreeSet

底层由TreeMap实现

基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。

2.1.2 HashSet【完成】

  基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息【由HashMap的数据存储行为有关系】,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。

  数据实现由hashmap实现, Key就是输入的变量。value是一个统一的Object数据

2.1.3 LinkedHashSet【完成】

  具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。【本质是不断的通过hash值计算来进行下一个数值的查找】

2.2,List

  • ArrayList:基于动态数组实现,支持随机访问【查找复杂度O(1),本质是一个数组】。

  • Vector:和 ArrayList 类似,但它是线程安全的【区别sychronized修饰,做了同步处理】。

  • LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。【普通for遍历每次都要重头开始,Iterator方法是有一个光标指向这里】不仅如此,LinkedList 还可以用作栈【LIFO】、队列和【FIFO,可以用来做生产者消费者设计模式】双向队列【集合前两种的功能】。https://www.cnblogs.com/ysocean/p/8657850.html

2.3,Queue【完成】

LinkedList:可以用它来实现双向队列【实现Deque 接口】。

PriorityQueue:基于堆结构---minHeap

  一个基于优先级的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。该队列不允许使用 null 元素也不允许插入不可比较的对象(没有实现Comparable接口的对象)。

  Java中PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示(任意一个非叶子节点的权值,都不大于其左右子节点的权值)

public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {

1>PriorityQueue是一种无界的,线程不安全的队列
2>PriorityQueue是一种通过数组实现的,并拥有优先级的队列
3>PriorityQueue存储的元素要求必须是可比较的对象, 如果不是就必须明确指定比较器【可以插入相同数据】

需要理解堆这个数据结构就很好办了

leftNo = parentNo*2+1

rightNo = parentNo*2+2

parentNo = (nodeNo-1)/2

3,Map

3.1,TreeMap

  基于红黑树实现。

3.2,HashMap【非线程安全】【完成】

  基于哈希表实现【这个详见Java-HashMap实现原理

3.3,HashTable【遗留类,直接跳过它使用cocurrentHashMap】【完成】

  和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。

  它是遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。

  类似于:HashTable中的锁类似于MySQL中的表级锁Segments全部锁定、ConcurrentHashMap 类似于MySQL中的行级锁单个Segment锁定

3.4,ConcurrentHashMap【分段锁Segments并发高效、线程安全

  HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

  ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

特色之处:

①可以看到ConcurrentHashMap会首先使用Wang/Jenkins hash的变种算法对元素的hashCode进行一次再哈希

② (hash >>> segmentShift) & segmentMask//向右无符号移动28位,意思是让高4位参与到hash运算中,

Segment小锁锁定数据各个数据默认16个,读

④执行 size 操作时,先不加锁两次结果相同,就直接使用使用这个结果;否则对每一个Segment加锁统计各个count和; 

JDK 1.7 使用分段锁机制来实现并发更新操作,核心类为 Segment,它继承自重入锁 ReentrantLock,并发度与 Segment 数量相等。

JDK 1.8 使用了 CAS 操作来支持更高的并发度,在 CAS 操作失败时使用内置锁 synchronized。

并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。

3.4,LinkedHashMap【继承HashMap,添加前后索引】【完成】

  使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。 https://www.jianshu.com/p/8f4f58b4b8ab

  然后把accessOrder【LinkedHashMap特有的】设置为false,这就跟存储的顺序有关了,LinkedHashMap存储数据是有序的,而且分为两种:插入顺序【head-tail】和访问顺序【0-(size-1)遍历顺序】。

  accessOrder设置为false,表示不是访问顺序而是插入顺序存储的,这也是默认值,表示LinkedHashMap中存储的顺序是按照调用put方法插入的顺序进行排序的

  header是一个Entry类型的双向链表表头,本身不存储数据。

  插入尾部、清楚头部

3.4.1 LinkedHashMap实现的LruCache【常用的数据缓存项】Android图片就是用的这个

Least Recently Used

package com.cnblogs.mufasa.Map;

import java.util.LinkedHashMap;
import java.util.Map; public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private int maxEntries;//设置的cache数据大小
public LRUCache(int maxEntries) {
super(16, 0.75f, true);
this.maxEntries = maxEntries;
} @Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
//插入新数据的时候判断是否超额
//是,清楚head-next数据,插入新数据在head-pre
//否,插入head-pre就行
return size() > maxEntries;
}
}
package com.cnblogs.mufasa.Map;

import org.w3c.dom.Node;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; public class Client {
public static void main(String[] args) {
// HashMap<Integer,String> hm=new HashMap<>();
// ConcurrentHashMap<Integer,String> chm=new ConcurrentHashMap<>(); //TreeMap
// TreeMap<Integer,String> map =new TreeMap<>();
// map.put(3, "val");
// map.put(2, "val");
// map.put(1, "val");
// map.put(5, "val");
// map.put(4, "val");
// System.out.println(map); // Integer integer=new Integer(1);
// System.out.println(Integer.parseInt("111",2));
// System.out.println(8^111); // String a1="hello";
// String a2=new String("hello");
// System.out.println(a1==a2); //
LRUCache<String,Object> cache = new LRUCache<>(3);
cache.put("a","abstract");
cache.put("b","basic");
cache.put("c","call"); cache.put("e","hello");
cache.put("d",null);
cache.put(null,"null");
cache.get("e");
cache.put("f","滴滴滴");
System.out.println(cache); // 输出为:{c=call, a=abstract, d=滴滴滴} }
}
/*
{null=null, e=hello, f=滴滴滴}
*/

3.5,WeakHashMap

3.5.1 存储结构

WeakHashMap 的 Entry 继承自 WeakReference,被 WeakReference 关联的对象在下一次垃圾回收时会被回收。

WeakHashMap 主要用来实现缓存,通过使用 WeakHashMap 来引用缓存对象,由 JVM 对这部分缓存进行回收。

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>

3.5.2 ConcurrentCache

Tomcat 中的 ConcurrentCache 使用了 WeakHashMap 来实现缓存功能。

ConcurrentCache 采取的是分代缓存:

  • 经常使用的对象放入 eden 中,eden 使用 ConcurrentHashMap 实现,不用担心会被回收(伊甸园);
  • 不常用的对象放入 longterm,longterm 使用 WeakHashMap 实现,这些老对象会被垃圾收集器回收。
  • 当调用 get() 方法时,会先从 eden 区获取,如果没有找到的话再到 longterm 获取,当从 longterm 获取到就把对象放入 eden 中,从而保证经常被访问的节点不容易被回收。
  • 当调用 put() 方法时,如果 eden 的大小超过了 size,那么就将 eden 中的所有对象都放入 longterm 中,利用虚拟机回收掉一部分不经常使用的对象。

核心源码:

public final class ConcurrentCache<K, V> {

    private final int size;

    private final Map<K, V> eden;

    private final Map<K, V> longterm;

    public ConcurrentCache(int size) {
this.size = size;
this.eden = new ConcurrentHashMap<>(size);
this.longterm = new WeakHashMap<>(size);
} public V get(K k) {
V v = this.eden.get(k);
if (v == null) {
v = this.longterm.get(k);
if (v != null)
this.eden.put(k, v);
}
return v;
} public void put(K k, V v) {
if (this.eden.size() >= size) {
this.longterm.putAll(this.eden);
this.eden.clear();
}
this.eden.put(k, v);
}
}

4,容器中的设计模式

4.1 适配器设计模式

java.util.Arrays#asList() 可以把数组类型转换为 List 类型。

A-适配器-B

@SafeVarargs
public static <T> List<T> asList(T... a)

4.2 迭代器模式

  让用户通过特定的接口访问容器的数据,不需要了解容器内部的数据结构

  

        LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
// for (String item : list) {
// System.out.println(item);
// }
Iterator<String> iterator=list.iterator();
Iterator<String> iterator2=list.descendingIterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}

4.3 引申-生产者消费者

  Queue队列可以直接当做这个模式的数据结构

Java容器汇总【红黑树需要再次学习】的更多相关文章

  1. Java集合详解6:这次,从头到尾带你解读Java中的红黑树

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  2. JAVA数据结构之红-黑树

    本篇博客我会重点介绍对红-黑树的理解,重点介绍红-黑树的查找,这里我们将要讨论的算法称为自顶向下插入,也就是把沿着树向下查找插入点 Ⅰ.平衡树和非平衡树 平衡树和非平衡树:当插入一组数据关键字是按照升 ...

  3. Java 1.8 红黑树

    红黑树 R-B Tree R-B Tree,全称 Red-Black Tree 又称为 红黑树,它是一种特殊的二叉查找树,红黑树的每个节点都有存储位表示节点的颜色,可以是红Red 或者 黑Black ...

  4. 数据结构Java版之红黑树(八)

    红黑树是一种自动平衡的二叉查找树,因为存在红黑规则,所以有效的防止了二叉树退化成了链表,且查找和删除的速度都很快,时间复杂度为log(n). 什么是红黑规则? 1.根节点必须是黑色的. 2.节点颜色要 ...

  5. 关联容器set的用法(关联容器,红黑树,)

    set和multiset会根据特定的排序准则自动将元素排序,set中元素不允许重复,multiset可以重复.// 2017/7/23号 好像set容器里面只能装一个元素 #include<io ...

  6. 关联容器map(红黑树,key/value),以及所有的STL容器详解

    字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s=“a1a2···an”(n>=0).它是编程语言中表示文本的数据类型.在程序设计中,字符串(string)为符号或数 ...

  7. java中treemap和treeset实现(红黑树)

    java中treemap和treeset实现(红黑树)   TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...

  8. 红黑树(五)之 Java的实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

  9. Java 7之集合类型 - 二叉排序树、平衡树、红黑树---转

    http://blog.csdn.net/mazhimazh/article/details/19961017 为了理解 TreeMap 的底层实现,必须先介绍排序二叉树和平衡二叉树,然后继续介绍红黑 ...

随机推荐

  1. JavaScript原型,原型链 ? 有什么特点?

    每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时, 如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会 ...

  2. MediaPlayer: 在不同控件之间实现视频的无缝切换的方法

    最近使用MediaPlayer + TextureView 实现了一个视频播放器,并且实现了它的横竖屏切换的效果,唯一美中不足的是在横竖屏切换的时候画面会卡顿一下,虽然也不影响播放,但是怕测试会报Bu ...

  3. MyBatis 插件之拦截器(Interceptor)

    参考 https://blog.csdn.net/weixin_39494923/article/details/91534658 //项目实际使用  就是在你进行数据库操作时,进行数据的第二次封装 ...

  4. Java并发包线程池之ForkJoinPool即ForkJoin框架(二)

    前言 前面介绍了ForkJoinPool相关的两个类ForkJoinTask.ForkJoinWorkerThread,现在开始了解ForkJoinPool.ForkJoinPool也是实现了Exec ...

  5. 创建Bitmap之BitmapFactory

    package com.loaderman.customviewdemo; import android.app.Activity; import android.graphics.Bitmap; i ...

  6. PAT 甲级 1063 Set Similarity (25 分) (新学,set的使用,printf 输出%,要%%)

    1063 Set Similarity (25 分)   Given two sets of integers, the similarity of the sets is defined to be ...

  7. iOS摄像头和相册(转)

    iOS摄像头和相册iOS 获取图片有三种方法1. 直接调用摄像头拍照 2. 从相册中选择 3. 从图库中选择 UIImagePickerController 是系统提供的用来获取图片和视频的接口: 用 ...

  8. 如何配置docker仓库

    创建文件 /etc/docker/daemon.json,写入国内镜像URL地址 { "registry-mirrors": [ "https://rq5uyt7.mir ...

  9. Vue 中 css scoped 样式穿透 ( stylus[>>>] / sass / less[/deep/] )

    scoped看起来很好用,当时在Vue项目中,当我们引入第三方组件库时(如使用element-ui),需要在局部组件中修改第三方组件库样式,而又不想去除scoped属性造成组件之间的样式覆盖.这时我们 ...

  10. 已经安装了VRay但3dmax的材质编辑器里没有VRay材质的解决过程

    已经安装了VRay但3dmax的材质编辑器里没有VRay材质怎么办? 众所周知,vray是一款很好用的渲染器,但是安装过程和使用当中总会出现各种问题.昨天我就遇到了,捣鼓半天终于解决,分享给大家自己的 ...