1.hash处理冲突的方法
hash表一种把键(key)代入到设计好的哈希函数中直接计算得到值得存储位置,时间复杂度为O(1)。
几个问题需要解决:1.哈希函数的构造 2.哈希冲突的解决 3.哈希表的增删改查
1.哈希函数的构造
1.除数留余法,(用的比较多),H(Key) = key % p (p ≤ m)
除数p的取值最好选择不大于集合数的最大的一个素数
哈希表长度 8 16 32 64 128 256 512
最大素数 7 13 31 61 127 251 503
2.直接地址法 3.数字分析法 4.平方取中法 5.折叠法
原则:地址与每一位的key都相关,来做到“散列地址”尽可能分散,减少哈希冲突为首要原则。
1.确保哈希表长度是一个素数,这样会产生最分散的余数,尽可能减少哈希冲突
2.设计好哈希表装填因子,一般控制在0.7-0.8
3.确认我们的数据规模,如果确认了数据规模,可以将数据规模除以装填因子,根据这个结果来寻找一个可行的哈希表大小
4.当数据规模可能会动态变化,不确定的时候,这个时候我们也需要能够根据数据规模的变化来动态给我们的哈希表扩容,所以一开始需要自己确定一个哈希表的大小作为基数,然后在此基础上达到装填因子规模时对哈希表进行扩容。
5.哈希表的扩容机制,直接扩容两倍和分摊转移,哈希冲突则用链地址法。Java/Redis 哈希扩容机制
2.哈希冲突解决方法
哈希冲突就是 不同的key值经过哈希函数计算之后的值得到的哈希地址一样,引起冲突。为了避免这种情况,需要再次计算哈希地址。
1.开放地址法:当发生冲突时,冲突的哈希值可以按照一定的di增量向哈希表后面(或者前面)的位置尝试存放,直到存放完成。
首先有一个H(key)的哈希函数
如果H(keyi)=H(key1)
那么keyi存储位置Hi=(H(key)+di)%m;m为表长
有如下几种探测方法:
1.线性探测 di=c∗i ;
2.平方探测 di = 12,-12,22,-22 ,…,q2,-q2
(q ≤ m/2);
3.随机探测
三种方法示例
2.链地址法:将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程中,当查找到这个链表时,必须采用线性查找方法。
2.内存分区模型
1.代码区:存放函数体的二进制代码,由操作系统进行管理的,通常代码区是可以共享,通常是只读,为了防止程序被意外的修改。
2.全局区:存放全局变量和静态变量以及常量,该区域的数据在程序结束后由操作系统释放。
3.栈区:由编译器、操作系统自动分配释放,存放函数的参数值、局部变量等
4.堆区:由程序员分配和释放。若程序员不释放,程序结束时由操作系统回收
3.数组与链表的区别
1.从内存上:数组需要提前申请足够的连续的空间,且不能动态调整数组的大小,数组一般是从栈中分配空间;链表相反,链表可以动态的申请内存和释放空间,而且链表的额内存空间可以不连续,链表一般是从堆上分配空间。
2.从访问操作上:由于数组空间的连续喝栈空间的方便快速,数组的下标查找效率很高,但是插入删除需要移动部分数组元素的位置,造成效率的低下。链表由于动态空间的分配以及指针的运用,插入删除操作开销极低。所以以上两者在应用场景上分别各有所长。
4.redis简介,其中的数据结构用过哪些,了解跳表?
Redis 是开源的,高性能的 key- value 非关系型数据库。
它用来减轻关系型数据库的压力,通过查询内存比查询数据库的效率高很多。
Redis 使用单线程模型,所以不需要考虑并发线程安全问题,同时也采用了I/O多路复用(epoll),单线程主要体现在处理I/O请求的时候,当然其他模块服务依然是多线程操作。所以单线程依旧可以处理高并发服务(通过 epoll 接受高并发请求)。
Redis 使用的是缓存淘汰策略,即淘汰最少使用的数据。
Redis 与数据库中的数据一致性的问题。如果对数据有强一致性的问题,不能使用缓存。
缓存雪崩问题:缓存同一时间大面积失效,导致所有的请求都涌向数据库,从而导致数据库崩掉。
解决: 给缓存叫上随机的失效时间,避免同一时间失效。使用互斥锁,但是牺牲了吞吐量。
缓存击穿问题: 黑客故意去请求缓存中不存在的数据,导致请求都怼向数据库,导致数据库崩掉。
解决: 利用互斥锁。提供一个能判断请求是否有效的拦截机制。
Redis优势:
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除。
各种数据类型适用场景:
(一)String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。(二)hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。(三)list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
(四)set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
(五)sorted set
sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP
N操作。另外,参照另一篇《分布式之延时任务方案解析》,该文指出了sorted set可以用来做延时任务。最后一个应用就是可以做范围查找
5.红黑树比平衡二叉树有哪些优点
平衡二叉树:利用左右子树高度差小于1的特点,主要解决了二叉树在极端情况下退化成为链表的情况。严格平衡的条件又使得插入、删除操作都要进行左旋、右旋的操作来使其重新保持平衡,开销过大。但是平衡二叉树的查找效率相对于红黑树来说还是稍高一点,时间复杂度和红黑树一样,都是O(logN)。
红黑树:属于不严格平衡二叉树,主要解决了平衡二叉树每次插入、删除节点后需要立马操作保证平衡的特性,从而减低了开销。红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。
红黑树主要用红黑两种颜色改变了平衡二叉树左右子树高度差必须小于或等于1的规定,红黑树的特点主要如下:
1.(二色)节点只有两种颜色,
2.(黑根)根节点只能是黑色
3.(黑叶)每个叶子节点也都是黑色
4.(路同黑)每一个节点到该节点的叶子节点的每条路劲上都包含数量相同的黑色节点。
5.(红生黑)如果一个节点是红色的,那么他的子节点必须是黑色。
记住:黑根黑叶路同黑,红黑二色红生黑。
红黑树在搜索、查找中因为非平衡的原因会稍逊与平衡二叉树,但是红黑树对插入删除的折中处理大大降低了重复平衡的操作开销,从这一点上来看是值得的。这也就是为什么STL中的map、set,java中的TreeSet、HashMap的底层搜索树都是用红黑树的结构来存储数据。
7.说说红黑树的特性
红黑树:属于不严格平衡二叉树,主要解决了平衡二叉树每次插入、删除节点后需要立马操作保证平衡的特性,从而减低了开销。红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。
红黑树主要用红黑两种颜色改变了平衡二叉树左右子树高度差必须小于或等于1的规定,红黑树的特点主要如下:
1.(二色)节点只有两种颜色,红色和黑色
2.(黑根)根节点只能是黑色
3.(黑叶)每个叶子节点也都是黑色
4.(路同黑)每一个节点到该节点的叶子节点的每条路劲上都包含数量相同的黑色节点。
5.(红生黑)如果一个节点是红色的,那么他的子节点必须是黑色。
记住:黑根黑叶路同黑,红黑二色红生黑。
红黑树在搜索、查找中因为非平衡的原因会稍逊与平衡二叉树,但是红黑树对插入删除的折中处理大大降低了重复平衡的操作开销,从这一点上来看是值得的。这也就是为什么STL中的map、set,java中的TreeSet、HashMap的底层搜索树都是用红黑树的结构来存储数据。
8.各种树,排序的时间复杂度
9.数据库索引,事务,事务级别
数据库的索引 B+ 多路搜索树,
事务 是定义的一个数据库的操作序列,这些操作要么全做,要么全不做,具有 原子性、一致性、隔离性、持久性等特点。
10.不考虑事务的隔离性会出现什么问题
会出现脏读、脏写、重复读、幻读,丢失更新等问题。
11.事务隔离级别
1、事务的并发问题
- 脏读:事务 A 读取了事务 B 更新的数据,然后 B还没有完成回滚数据操作,所以 A 读取到的数据是脏数据
- 脏写:事务 A 在执行过程中脏写了事务B提交的更新的新数据,导致了 事务A 在回滚操作中将数据重新更改。
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了修改更新并提交,导致事务A多次读取同一数据时,结果不一致。
- 幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。主要针对数据的插入删除。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
事务的隔离级别越低,可能出现的并发异常越多,但是通常系统的并发能力也更强。
常见的并发控制技术:
乐观锁:对于并发执行可能冲突的操作,假定不会产生冲突,允许并发执行,带到问题产生时在去解决问题
悲观锁:对于并发执行可能冲突的操作,假定其必定发生冲突,通过加锁来使得并行的操作串行执行。
12.索引的类型
一、索引方法
Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。
-
FULLTEXT
即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。
全文索引并不是和MyISAM一起诞生的,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。 -
HASH
由于HASH的唯一(几乎100%的唯一)及类似键值对的形式,很适合作为索引。
HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。 -
BTREE
BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口 root 开始,依次遍历 node,获取 leaf,这是MySQL里默认和最常用的索引类型。 -
RTREE
RTREE在 MySQL 很少使用,仅支持 geometry 数据类型,支持该类型的存储引擎只有 MyISAM、BDb、InnoDb、NDb、Archive 几种。
相对于 BTREE,RTREE 的优势在于范围查找。
二、索引类型
主键索引:数据记录里面不能有 null,数据内容不能重复,在一张表里面不能有多个主键索引。
唯一索引:字段数据是唯一的,数据内容里面能为 null, 在一张表里面,是可以添加多个唯一索引。
普通索引:使用字段关键字建立的索引,主要是提高查询速度
全文索引:对文本的内容进行分词,进行搜索