线性表结构:线性表:数组、链表、栈、队列前端
1.数组:连续的内存空间。java
1.1 查找:随机查找的时间复杂度为O(1),注意,只是随机查找(用下标的方式)。排序后的二分查找时间复杂度O(logn)数据库
中间插入和删除:须要搬移元素位置,时间复杂度为O(n)编程
开头和结尾插入和删除:O(1)后端
插入优化技巧:若是条件容许,插入到第K个位置时,能够把第K个位置的元素移动到最后,减小数据搬运数组
删除优化技巧:若是条件容许,能够几个删除一块儿后,再搬移元素。(相似JVM的垃圾回收,标记清除法)
1.2 JAVA中的ArrayList封装了数组,相比数组优点:动态扩容。浏览器
(1)扩容时,新建一个大的数组,而后数据拷贝到这个新的数组。缓存
(2)扩容大小:原来容量的1.5倍数据结构
(3)数组和ArrayList的选择:通常使用ArrayList,可是对于底层框架的开发,须要把性能作到极致,能够选择数组。并发
1.3 二维数组能够表示矩阵
针对稀疏矩阵的表示:若是直接表示会浪费存储空间。能够采用三项式来表示。
A(0,1)表示矩阵的行数
A(0,2)表示矩阵的列数
A(0,3)表示矩阵的非零项的总数
A(i,j,value) 表示非零的项。i从1开始,第i行第j列的值为value
1.4 数组和多项式
P(x) = a0 + a1x + a2*x^2 + a3*x^3 + ... + + an*x^n
好比 2x^5 + 3x^4 + 5x^2 + 4x + 1
方法一:使用n+2长度的一维数组存储,第一个元素是最大的指数n,其他元素按n递减存储多项式的系数。若是没有的存储0
A = {5,2,3,0,5,4,1} ,其中这里没有x^3的系数,因此第四项为0
缺点:若是有x^100,那么素组的长度为100+1
方法二:只存储多项式非零项。第一个元素为多项式非零项的个数。
A = {5,2,5,3,4,5,2,4,1,1,0}
缺点:计算时可能会更复杂些
2.链表:不要求内存空间连续
2.1 插入和删除:适合大量的操做 O(1);查询: O(n)
2.2 JAVA中的LinkedList为双向链表,有next也有previous
LinkedList能够实现栈、队列以及双端队列等数据结构
LinkedList能够实现LRU缓存机制
2.3 单向链表:指针和数据(第一个接节点是链表头指针,最后一个指针设置为null)
循环链表:最后一个指针指向链表头部,从任何一个节点入手,能够遍历全部其余节点
环形链表:一般应用于内存工做区与输入/到处缓冲区
双向链表:优点是能够轻松找到先后节点
双向循环链表
2.4 链表和多项式:和数组的方法同样,只是链表实现的好处是适合多项式内容变更
2.5 环形链表能够实现稀疏矩阵:优势是矩阵变动时不须要大量移动数据
3.跳表(跳跃表):经过多级索引使得链表可以实现二分查找,加速链表的随机查询效率,似于二分查找。
查询(不支持随机查询):O(logn)
空间复杂度:O(n)
场景: Redis使用了跳表。
HBase MemStore的也使用的跳表。为何呢?
HBase 属于 LSM Tree 结构的数据库,LSM Tree 结构的数据库有个特色,实时写入的数据先写入到内存
内存达到阈值往磁盘 flush 的时候,会生成相似于 StoreFile 的有序文件,而跳表刚好就是自然有序的
因此在 flush 的时候效率很高,并且跳表查找、插入、删除性能都很高,这应该是 HBase MemStore 内部存储数据使用跳表的缘由之一。
HBase 使用的是 java.util.concurrent 下的 ConcurrentSkipListMap()。
4.栈:先入后出,当作桶。(操做受限的数组或链表结构)
4.1 添加、删除复杂度都是O(1);查询: O(n)
4.2 能够数组实现(顺序栈)和链表实现(链式栈)(数组不利于大小动态变化,可是优势是编程简单)只须要一个top指针指向栈顶元素。
4.3 应用:浏览器前进后退
函数调用
表达式取值
5.队列Queue:先入先出,通俗理解:排队。(操做受限的数组或链表结构)
5.1 添加、删除复杂度都是O(1);查询: O(n)
在高级语言中,通常不用纯粹的栈和队列,java能够用双端队列替代。
5.2 能够数组(顺序队列)和链表(链式队列)实现。
线程池中的各类策略:
链表实现:无界队列,不合适响应时间敏感的。
数组实现:有界队列,适合响应时间敏感的。
环形队列与链式队列的选择:若是能够肯定最大的大小,那么选择环形队列。若是不能肯定,那么选择链式队列。
5.3 须要两个指针front和rear分别指向前端和后端。
5.4 应用:做业调度、磁盘的缓冲区。
5.5 双端队列Deque:两边均可以进出。两边都须要front和rear指针。
5.6 循环队列 : MapReduce中Shuffle时使用了。
注意:环形队列是使用数组实现的,解决顺序队列的数据搬运问题。
5.7 优先队列Priority Queue
插入和删除:O(1)
取出操做:O(logn),按照优先级
底层实现能够多样:heap、bst、treap
java中实现:PriorityQueue
5.8 阻塞队列和并发队列(CAS)
6.哈希表Hash table(散列表):经过哈希函数(散列函数)映射值。
6.1 模型:Hash函数获得数组下标 -> 数组(链表做为数组的元素)
插入和删除:O(1)
查询:O(1)
说明:可能后面链表查询的复杂度不为1,可是通常hashCode一致的比较少,
因此链表的元素个数其实颇有限,能够认为就是O(1)。
6.2 哈希函数
(1)除后取余数法
(2)平方取中
6.3 java 7中的HashMap是数组和链表的结合体。JAVA 8中是数组 + 红黑树实现。
(1)对象的HashCode是用来在散列存储结构中肯定对象的存储地址的。
(2)若是两个对象的HashCode相同,即在数组中的地址相同。而数组的元素是链表。这两个对象会放在同一链表上。
(3)如何肯定是同一个对象? 经过equals方法。
(4)HashMap默认的加载因子是0.75,默认最大容量是16。
所以能够得出HashMap的默认实际容量是:0.75*16=12,到了12就会扩容。
扩容大小:扩容原来的一倍。
还有经常使用的 HashMap HashSet。
7. 应用:算术表达式的表示方法
中序法(操做数1-运算符-操做数2): 2*3 + 4*5
中序表达法符合人的习惯,不过计算机处理不方便
前序法(运算符-操做数1-操做数2): +*23*45
经常使用的计算机处理方式
后序法(操做数1-操做数2-运算符): 23*45*+
经常使用的计算机处理方式(比前序经常使用)
7.1 利用堆栈实现表达式运算:最简单的是后续表达式求值-只须要一个栈。
7.2 可使用二叉树的方法
7.3 中序转前序/后序
2*3 + 4*5
(1)括号法: 先括号括起来((2*3) + (4*5))
中序转前序
用括号内的运算符替代左括号,近者优先:+*23)*45))
去掉全部右括号:+*23*45
中序转后序
用括号内的运算符替代右括号,近者优先:((23* (45*+
去掉全部左括号:23*45*+
(2)堆栈法
7.4 前序或后序转中序
(1)括号法
(2)堆栈法