前两天面试阿里,最终死在了算法和数据结构上,痛苦不已。今天下了决心,来撸一把算法和数据结构。
对于计算机来说,只有0110,它是不会关心什么算法,什么数据结构的。那么,谁关心呢?当然是人啊。计算机是很傻逼的东西,它能做什么,完全取决于你想让它做什么。于是,就有了算法和数据结构。数据结构用于存储,算法用于计算。
1. 数据结构
在接触算法前,你需要先了解数据结构。数据结构分为三层:
(1) 逻辑结构(抽象层):
集合结构:表示数据可以合成一个整体,但彼此间没有任何联系,如数组;
线性结构:数据间有一对一的关系,如队列;
树形结构:数据间有一对多的关系,如二叉树;
网状结构:数据间有多对多的关系;
(2)物理结构(结构层(存储方式)):
顺序结构:元素存在一定的连续空间内,如数组。特点是查询快,插入和删除慢,扩容复杂;
链式结构:元素没有存在连续的空间内,每个节点都持有一段数据和下一个元素的位置。特点是查询慢,插入删除快;
(3)运算结构(实现层):
创建和销毁(分配资源、建立结构、释放资源)、
插入和删除、
查询和修改(遍历和迭代、随机访问)、
排序和查找(算法应用)。
2. 堆栈和队列
堆栈特点是:先进后出、后进先出。
队列特点是:先进先出。
堆栈和队列都可以用数组或二叉树实现。
阿里面试的时候问到了队列相关的问题:
(1)怎么实现一个队列?
初始化一个数组(链表也可以),用来存储元素。设定只能从一端插入数据,从另一端取数据,就形成了列表。
(2)如果(用数组实现的)队列满了怎么办?
那就从初始位置继续存元素(前提是元素已经被取走)。
(3)怎么判断一个队列是空队列还是满队列?
无论是数组实现,还是链表实现,都需要记录队列的头、尾和指针(记录下一个元素位置)。当指针所在的位置是头且不存在任何元素时,就是空的;当指针下一个位置是头时,就说明队列满了(就挂在这了)。
(4)有界队列和无界队列(滴滴面试题目)
用数组实现的队列,需要指定初始容量,是有界队列;用链表实现的队列,可以无限的添加元素直到内存崩溃,是无界队列。
(5)题外话:ArrayList和HashMap的初始容量满了以后,会发生什么事?LinkList为什么不用担心容量问题?
妈的,扩容啊!ArrayList基于数组实现,HashMap基于数组和链表实现,容量不够当然得扩容了。LinkList基于链表,理论上来说,直到内存奔溃,它可以无限制的添加元素。
3. 链表和二叉树
啥是链表,啥是二叉树?
在计算机中,数据的存储位置是可以不连续的,只要每个数据块都能记住下一个数据块的位置就能完成数据的存储和查询了。这样做的好处是,不需要计算机一次性的分配那么大的连续空间。这种数据结构就是链表了,其中的数据块就叫做节点。如果每个节点不止记录下一个节点的位置,还记录了上一个节点的位置,那它就构成了双向链表。那前边的自然就是单向链表了。
那二叉树呢?针对单向链表,对每一个节点都进行一次裂变(都能产生两个子节点),那么,二叉树就产生了。
说到这两货,就不得不提到HashMap了。JDK1.7之前HashMap是用数组和链表实现的。JDK8默认也是数组加链表,当某一个链表的元素个数达到8个时(英文注释中说的是远大于2),自动切换成红黑树(二叉树的一种)。为什么会这样呢?数组和链表逐个遍历的话,时间复杂度是O(n),但是二叉树的时间复杂度是O(logN),会发现查询的时间快了很多。
本文参考自:数据结构(1)—— 数据结构的三大结构