Java容器汇总【红黑树需要再次学习】

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会首先使用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容器汇总【红黑树需要再次学习】的更多相关文章
- Java集合详解6:这次,从头到尾带你解读Java中的红黑树
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
- JAVA数据结构之红-黑树
本篇博客我会重点介绍对红-黑树的理解,重点介绍红-黑树的查找,这里我们将要讨论的算法称为自顶向下插入,也就是把沿着树向下查找插入点 Ⅰ.平衡树和非平衡树 平衡树和非平衡树:当插入一组数据关键字是按照升 ...
- Java 1.8 红黑树
红黑树 R-B Tree R-B Tree,全称 Red-Black Tree 又称为 红黑树,它是一种特殊的二叉查找树,红黑树的每个节点都有存储位表示节点的颜色,可以是红Red 或者 黑Black ...
- 数据结构Java版之红黑树(八)
红黑树是一种自动平衡的二叉查找树,因为存在红黑规则,所以有效的防止了二叉树退化成了链表,且查找和删除的速度都很快,时间复杂度为log(n). 什么是红黑规则? 1.根节点必须是黑色的. 2.节点颜色要 ...
- 关联容器set的用法(关联容器,红黑树,)
set和multiset会根据特定的排序准则自动将元素排序,set中元素不允许重复,multiset可以重复.// 2017/7/23号 好像set容器里面只能装一个元素 #include<io ...
- 关联容器map(红黑树,key/value),以及所有的STL容器详解
字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s=“a1a2···an”(n>=0).它是编程语言中表示文本的数据类型.在程序设计中,字符串(string)为符号或数 ...
- java中treemap和treeset实现(红黑树)
java中treemap和treeset实现(红黑树) TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...
- 红黑树(五)之 Java的实现
概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...
- Java 7之集合类型 - 二叉排序树、平衡树、红黑树---转
http://blog.csdn.net/mazhimazh/article/details/19961017 为了理解 TreeMap 的底层实现,必须先介绍排序二叉树和平衡二叉树,然后继续介绍红黑 ...
随机推荐
- Android:Mstar Android8.0平台音量控制流程
一.Speaker 音量.静音流程分析 java层音量设置首先调用到的是AudioManager.java中的方法,在这里有两种方法可以设置音量 setStreamVolume 和 adjustStr ...
- python 中 staticmethod 和 classmethod有什么区别
面试中经常会问到staticmethod 和 classmethod有什么区别? 首先看下官方的解释: staticmethod: class staticmethod staticmethod(fu ...
- springboot拦截json后缀的请求,返回json数据
需求:请求list.json返回以下数据 { "jsonResult": { "code": 200, "message": "查 ...
- MySQL从.ibd文件中恢复数据
首先,在MySQL命令行下执行如下命令可以查看MySQL中存放数据的位置: show global variables like "%datadir%"; 我这里的执行结果: +- ...
- iOS-图形绘制(全)
画阴影: CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(contex ...
- 安装CCS提示错误Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机
问题如图所示: 解决方案: 放在D:\目录下 windows键+X 选择 命令提示符(管理员) 一定要是管理员 打开cmd 分别执行下面两句.红色部分就是自己的更新程序了.其他安装同理 例如Wi ...
- 图像Resize中0.5像素中心对齐的问题
目录 0.5像素对齐的问题 0.5像素对齐的问题 1. 问题提出 在进行图像缩放时,偶尔会看到一些比较奇怪的代码,其中有一个就是0.5像素中心对齐的问题,例如在OpenCV线性插值的代码中有类似如下操 ...
- 解决移动端1px的问题,设备像素比devicePixelRatio的应用
本文主要针对移动端1物理像素问题展开 解决这个问题先要了解一下概念: CSS像素(CSS Pixel):(通俗说:样式中写的值)就是我们在样式代码中常写的逻辑像素,是一个抽象概念,实际并不存在 设备独 ...
- 《C语言程序设计》学习笔记(二)
第八章 函数 函数的基本概念 定义:函数由函数名.参数和函数体组成. 函数定义的一般形式: 类型说明符 函数名(形式参数声明) { [说明与定义部分] 语句: } 说明: 1.类型说明符用来说明函数的 ...
- 【数据库开发】在Windows上利用C++开发MySQL的初步
[数据库开发]在Windows上利用C++开发MySQL的初步 标签(空格分隔): [编程开发] Windows上在上面配置环境的基础上开展一个小demo链接数据库,没想到中间也出现了这么多的问题,简 ...