前言
按照原计划,今天开始数据结构专栏的博文,数据结构系列博文是我在学习数据结构时总结所得的。不知道是否有人和当初的一样,出去面试的时候,不管面试的什么岗位,尤其是在bat,特别喜欢问一些数据结构或者操作系统方面的知识,可能你所在职位的技术能力很强但是因为数据结构不熟悉被pass了,这个时候你就会有怨言,只要我**技术好不就行了吗,为什么要会那些在工作用用不到的呢,OK,后半句说的没错,数据结构在日常的开发中直接用到的确实不多,但前半句是有矛盾的,可以这么说,如果你不熟悉数据结构,最多说在某个技术领域可以满足基本的业务需求不可能是技术好的体现。
一、不要把CURD没毛病,误认为自己技术够硬
我是17年7月份出来工作,18年6月份本科毕业的,在此期间也面试了一些公司,可能是因为大学时有些许项目经验的缘故,那个时候的自己还是比较自信的,我经常和朋友说,如果现在让我出去面试,我肯定不会像之前那么自信,因为我发现我只是一个会做CURD的码农,不算一个合格的思想程序员!
我们面试的时候经常会在简历上写上,熟悉使用***框架,***黑科技,但是有没有想过你可能会的只是使用,仅仅是使用,是使用而已,无论你是做什么开发,就算把最新的框架学会用了,也无济于事,你有阅读过框架的源码吗?熟悉框架的设计思想吗?或者说你简历上写了一大堆项目经验看似很丰富,但总结起来就是每个项目你都是做的CURD,所有项目用的都是同一种技术,其实这样还不如不把这样的项目经验写上去,而学习数据结构更有利于我们分析源码,是进阶路上必须过的一道坎儿~
做我们技术这一行其实好多时候也看工作经验,包括职位晋升等如果你有个3、5年工作经验可能更有优势,但是做了三年CURD,靠着三年经验成为了一个管理层人员的话,可惜的是这是一个只会CURD的管理层,当然,每个人的追求都不同,在这个现实的社会中不一定自己很努力就一定能有我们想要的结果,但是努力是我们真正成功的唯一道路!
二、链表和数组
说到数据结构,很多人的第一反应是想到了大学学C语言时编写的数据结构代码,但C语言只是一种实现方式,数据结构可以用任意编程语言来实现。
2.1 数组
数组是什么?专业些说,数据是一种线性表数据结构,它用连续的内存空间来存储一组具有相同类型的数据,线性表不用说了,排成一条线的数据结构就是线性表,比如数组、队列、链表、栈等,相反没有排成一条线的数据结构就是非线性表,比如二叉树、图等,那么数组的最大优势是什么?答案是随机访问,因为内存地址是连续的,而链表就不可以,链表我们在查找某一项的时候必须要循环遍历到那个点才可以,那么数组如何实现随机访问呢,看下图
上图所示,我们新建了一个大小为4的整形数组,其中内存块的首地址为10,因为整型数据占四个字节,所以内存块为该数组分配了10~25的内存空间,如果我们要访问某个下标的数据就要访问某个下标的地址则有公式:
a[i]_address = baseaddress + i *data_size
baseaddress就是内存块的基地址,data_size是数据类型的大小,所以看到这里你知道为什么大多数语言数组的下标都是从0开始的吗?
如果数组的下标是从0开始的,那么访问某个下标的地址公式上所示,如果数组的下标是从1开始的,访问某个下标的地址公式则变为:
a[i]_address = baseaddress + (i - 1)*data_size
这样的话我们每次随机访问数组,都多做了一次减法运算,而对CPU来说就是多做了一次减法指令。
什么时候用数组什么时候用链表要根据具体情况而定,比如我们说的数组的最大优势是随机访问,但是插入和删除数据就会变得很麻烦,因为数组的内存是连续的,所以当我们插入或者删除一个数据的时候,为了保证内存的连续性,我们可能要将这个元素后的数据整体往后迁移或者往前移动,这个时候时间复杂度就会大大升高,而链表在这方面就方便了很多。
2.2 链表
在这里我们主要说链表和数组的不同之处,详细的链表介绍会在后续文章中介绍,链表存储的数据并不是一块连续的内存空间,它是通过“指针next”将一些零散的内存块串起来,所以链表是不支持随机访问的,在上面我们也提到了。
内存块就是链表的接点,为了将所有的接点串起来,我们还需要记录链上的下一个接点的地址,而记录的这个东西我们称为后继指针next,为什么叫做后继指针呢?因为链表中还有双向链表,顾名思义每个接点不仅记录下一个接点的地址还要记录前一个接点的地址。
链表和数组相比虽然不支持随机访问,但链表内存不连续的特性让操作和删除变得异常简单,我们只需要将插入位置的数据被前一个接点的指针指向和自己原前一个接点指向的那个接点就可以了。删除也是如此,所以链表插入和删除数据的时间复杂度是O(1)。
数组的大小是固定的,申请了即使没使用也占用了这么大的内存空间,如果数组的内存空间不够用,我们就要申请一个更大的空间把之前的数据拷贝进去,而链表天然支持动态扩容,当然Java中的ArrayList也支持动态扩容,根据ArrayList底层实现我们知道,当ArrayList的内存空间不够用的时候,会自动申请一个1.5倍的内存空间,然后将之前的数据复制到新内存,但是当数据量特别大的时候效率也可想而知了!
三、做一个有思想的程序员
做一个有思想的程序员主要还是说不要做代码的搬运工,精通CURD只会让你越来越危险(ps:虽然我还没精通CURD),现在的新语言涌现的太多太多,比如RN、Kotlin、Flutter等或者是什么人工智能等一些很火的技术,每当这些新技术出来的时候可能都会冲击着我们的思想,因为我们总会想说哪个新技术会替代**,掌握新技术才能找到月薪**,你就会变得很恐慌,于是你抓紧时间去学了新技术,可能是工作原因时间不足,也可能是自己没有坚持下去,新技术没学成,自己还是会天天担忧,就像好多年前都说Android技术不行了,***会取代***,到现在Android还是活的很好,只是它的发展到了一个瓶颈期,需要更高端的技术人才,毕竟2010年左右Android才刚刚兴起。
做一个有思想的程序员不做代码的搬运工,不随波逐流,所有的语言都是相通的,语言会变,而数据结构和底层的一些东西不会变,所以学好了数据结构和算法,才能以不变应万变。
欢迎关注我的微信公众号代码男人,后台回复关键字微信,加入代码男人技术交流群,和我一起从今天开始进阶!