常用数据结构
前言
数据结构有很多,衍生出来的算法题,在LeetCode上已经有1611道,还记得一年前看的时候,才是1200+......
感叹时间真快,但是算法本质的东西,也就那点,无外乎:if..else判断;for循环,while循环,recursion递归......
每当大家谈起数据结构,最基本,最印象深刻的莫过于下面几种,见下文。
正文
正文,从互联网的历史出发,了解一些数据结构之外的内容,开阔自己的视野。
后续,从简单的线性表,到非线性表,汇总最基本的数据结构,更加详细的算法与数据结构,参考:https://github.com/Kate-liu/LeetCode
一、互联网企业的那些事
2009年的互联网,就业向往的是微软,Oricle,IBM这样外资IT巨头
国内最好的IT公司是联想,用友等
技术研发能力,国内互联网公司技术落后传统企业
阿里巴巴最核心的数据存储依赖的是IBM,Oracle,EMC的解决方案,即IOE
真正互联网公司崛起大概是移动互联网开始出现,互联网的渗透率得到加速
经历了前期时间的积累,互联网企业主导的各种分布式技术,大数据技术,移动互联网技术,云计算技术,超过传统IT巨头
目前互联网大厂的核心技术和业务模式在十几年前就已经奠定了,经过几年的摸索,大概在移动互联网前就开始稳定成熟
互联网企业的技术实力和商业能力是在这些企业还默默无闻的时候就发展起来的,而当其成为明星之后,并没有实质性的进展
所谓的互联网大厂,最近几年,并没有什么值得称道的商业模式创新和技术创新
十多年前,可能是一些并不优秀的技术人员,加入了一个并不出名的公司,然后这些人开创了一个杰出的事业,即二流的人做一流的事
然后公司开始挑选一流的人,结果似乎只是在维持这个事业,并没有开创更加杰出的事业
自己不需要追逐当前所谓热门技术,而应该好好想想需要为自己的未来准备些什么
二、数据结构之数组
创建数组必须要内存中一块连续的空间,并且数组中必须存放相同的数据类型
根据数组下标,就可以计算得到这个数据在内存中的位置
根据索引访问,时间复杂度为O(1)
随机快速读写是数组的一个重要特性
需要知道数组的下标
只是知道数组中数据的值,则只能遍历整个数组,时间复杂度为O(N)
在数组中插入,删除一个数据,需要改变数组的连续内存空间大小,重新分配内存空间
三、数据结构之链表
链表可以使用零散的内存空间存储数据
因为链表在内存中的数据不是连续的,链表中的每个数据元素,都必须包含数据和指向下一个数据元素的内存地址指针
在链表上查找一个数据,只能遍历链表,时间复杂度为O(N)
在链表中插入和删除数据,操作简单,时间复杂度为O(1)
链表结构简单,但是各种组合变换操作很复杂,两个单链表的合并问题
如何快速判断两个链表是否合并,如果合并,找到合并的元素?
思路1:将短链表遍历,key=内存地址,value=元素,放入Hash表,遍历长链表,在Hash表中查找Key是否存在。存在即为合并。
思路2:比较链表的长短,每一次都是长链表走 差值的 步数,接着循环遍历等长的链表,判断是否相等。相等即合并。
四、数据结构之Hash表
软件开发需求
知道部分数据查找完整数据
知道商品ID,查找完整的商品信息
知道词条名称,查找百科词条中的详细信息
Hash表的数据,以Key-Value的方式存储
Hash表的物理存储其实是一个数组,只需要根据Key计算出数组的下标,就可以快速找到结果
编程语言支持获得任意对象的HashCode,java在Object(java.lang.Object)中存在,返回一个int类型的值
利用这个Int类型的HashCode计算数组下标,最简答的方法就是余数法
根据Hash表的长度。对HashCode取余,余数即为Hash表数组的下标
Hash冲突,取余的时候,不同值对应相同的位置,此时使用链表法解决Hash冲突
实际,存储在Hash表中的数据,并不直接是数据,而是数据在内存中的地址指针
存在Hash冲突的时候,将不同的地址指针,添加到链表中,查找的时候遍历链表即可
极端情况下,Hash表会退化为一条链条,时间复杂度为O(N)
线性表
数据按照线性组织存放
每个数据元素的前面只能有一个(前驱)数据元素
每一个数据元素的后面只能有一个(后继)数据元素
数组和链表属于线性表
栈和队列属于操作受限的线性表
非线性表
树
五、数据结构之栈
在线性表的基础上加上操作限制条件,得到栈
限制条件:后面添加的数据,在删除的时候,必须先删除,即“后进先出”
类似于一个大桶放食物(吃东西),叠盘子(取盘子)场景
由于栈不需要随机访问,不需要中间添加,删除数据,可以使用数组实现,也可以使用链表实现
程序运行的时候,方法的调用需要栈来管理每一个方法的工作区,不管方法如何嵌套,栈顶元素始终是当前正在执行方法的工作区
六、数据结构之队列
队列是一种操作受限的线性表,限制:先进先出
软件运行期,资源不足情况
提交任务线程池执行,线程已经用完了,任务放入队列中
线程运行访问数据库,数据库连接用完了,线程进入阻塞队列
超市货架摆放食品的时候,前面是旧的,后面是新的,类似一个队列
七、数据结构之树
开发OA系统,部门的组织结构就是一棵树
编写的程序在编译的时候,第一步就是将程序代码生成抽象语法树
树的遍历,使用递归方式,使用设计模式中的组合模式
结束语
文中涉及的知识包括:数组,链表,Hash表,栈,程序栈,队列,树,时间复杂度。
需要记住的几点:
1.记住常见数据结构的时间复杂度,不要背,需要理解,比如:链表的删除时间复杂度真的是O(1)吗?其实,深究就并不是简单的直接删除了,首先需求查找到删除的位置,如果单向链表还需要在遍历一下,找到前驱结点,双向链表则不需要。
2.一般的hash表,重点是如何根据hash值,均匀存储数据,降低hash冲突,而不是如何存储数据,解决hash冲突,最基本的方式就是使用链表,存储冲突数据。
3.数据结构,衍生出来的算法与算法思想有很多,如分治,回溯,搜索,动态规划,贪心,数学,几何等。