java集合

java集合

Collection 单列集合

Map 双列集合

时间复杂度分析:常对幂指阶

代码执行时间不随n的增大而增大,时间复杂度为O(1)

数组:连续内存空间 相同数据类型

数组索引从0开始

寻址公式:数组首地址+索引*元素类型大小

若从1开始,公式中需要增加一次减法操作,cpu多了一次指令

ArrayLIst

动态的数组实现,占用连续内存

初始容量为0,第一次添加数据初始化为10

每次扩容为原来的1.5倍

添加

size+1是否满足

不满足grow扩容为原来的1.5倍

添加元素到size的位置

返回添加成功boolean值

ArrayList list=new ArrayList(10)中的list扩容0次

声明和实例,指定容量为10,未扩容

数组和List之间的转换

数组转LIst Arrays.asList

List转数组 List.toArray

数组转List,修改数组内容List受影响

底层使用Arrays类中的一个内部类ArraysList构造的集合

对传入数组进行包装,最终指向同一片内存

List转数组,修改List内容数组不受影响

底层进行了数组的拷贝

LinkedList

双向链表实现,头尾指针都有,内存利用率低

ArrayList和LinkedList

线程不安全

在方法内部使用,局部变量是线程安全的

使用线程安全的ArrayList和LinkedList

List syncArrayList = Collections.synchronizedList(new ArrayList<>()); List syncLinkedList = Collections.synchronizedList(new LinkedList<>());

二叉树:数组存储 链式存储

二叉搜索树 二叉查找树 有序二叉树 排序二叉树

最坏情况,二叉查找树退化成链表,查找时间复杂度O(n)

红黑树

左根右 根叶黑 不红红 黑路同

HashMap

散列表+红黑树+链表

散列表(hash表)根据键直接访问在内存存储位置值的数据结构 数组 随机访问

散列冲突,哈希碰撞,哈希冲突 多个key映射到同一个数组下标

散列表每个下标位置称作桶或者槽,每个桶对应一个链表,散列值相同放到同一个链表中

平均情况下拉链法查找时间复杂度为O(1)

最坏退化为链表O(n),故引入红黑树,查询时间为O(logn)

DDOS攻击

分布式拒绝服务攻击(攻击的发出点分布在不同位置)

不同位置的多个攻击者同时向一个或数个目标发动攻击

HashMap实现原理

底层hash表,数组+链表/红黑树

put元素:利用key的hashCode重新hash计算当前元素数组中的下标

存储hash值相同的key

key相同覆盖,key不同,即冲突添加

链表长度大于8且数组长度大于64转换为红黑树

扩容resize,红黑树拆分的树节点小于等于6,退化为链表

JDK1.7之前使用拉链法

扩容阈值=数组容量*加载因子

HashMap时懒惰加载,创建对象没有初始化数组

默认加载因子0.75

put方法具体流程

1.判断数组table是否为空或者NULL,是则执行resize()扩容(初始化)

2.根据键值key计算hash得到数组索引

3.table[i]==null 直接新建节点添加

4.table[i]!=null

4.1 判断首个元素key是否相同,同则覆盖

4.2 是否为红黑树,是则插入红黑树中,发现key存在,则覆盖

4.3 遍历链表,有相同key覆盖,没有则进行尾插,链表长度大于8转换成红黑树

5.插入成功后,判断所有键值对的数量size是否超过了最大容量(数组长度*0.75),

超过扩容,注意这里和一共使用了多少个桶无关,只要总数超了就扩

扩容机制

初始化需要调用resize扩容,第一次添加数据初始化长度为16

扩容阈值 数组长度*0.75

每次扩容都是扩容之前的两倍

扩容是创建新数组,老数组数据挪到新数组中

没有hash冲突的节点,e.hash&(newCap-1)计算新的索引位置

红黑树的节点会被拆分为两个链表,超8变树

链表 拆分链表 判断e.hash&oldCap是否为0,

0为原始位置,1为原始位置+增加的数组大小

寻址算法

扰动算法,hashcode高16位和低16位异或,使hash值更加均匀,减少hash冲突

(n-1)&hash 得到数组中的索引,代替取模,性能更好,数组长度必须是2的n次幂

HashMap的数组长度一定是2的次幂

(n-1)&hash 得到数组中的索引,代替取模,性能更好

扩容时重新计算索引效率更高

hash&oldCap==0的元素留到原位置,否则新位置=旧位置+oldCap

hashMap多线程下死循环(数组+链表)

数组扩容使用头插法,数据迁移导致死循环

两个线程同时扩容的时候会出现这个问题

你可能感兴趣的:(八股,java)