面试官问你:程序=算法+数据结构,能深入讲讲吗?

前言

大家好,我是你们的老朋友青戈,最近一位粉丝私信我倾诉自己面试的悲惨经历,说自己快毕业了,很多同学们都找到了满意的offer,唯独他自己面试被虐的很惨,到现在一个offer都没有,着急的不行。

细聊下来才知道,他学的专业是自动化,但是呢本专业的工作实在难找,于是把目光转向了热门行业:计算机,一方面薪资高,另一方面也感觉做IT非常有面子(关于这点我不知道从何说起,我们是苦逼的码农啊)

那我就问他面试之前有没有好好准备一下呢?(我猜他是没准备)

果然,他说自己就看了一点Java基础的知识(很虚),做了一个模仿天猫商城的实战项目,匆匆忙忙就去面试了,在面试的过程中被问到算法、数据结构这些,完全是一脸懵逼,最后几个回合就败下阵来,灰头土脸的回学校了。

看到同学们纷纷拿到了满意的offer,开始出去聚餐庆祝了,他也没敢跟着去,怕丢脸…

基于这位粉丝非常尴尬的处境,我决定撸一篇关于计算机基础的科普文章。可别小看这些基础,在面试的过程中,计算机基础是重点考察的目标,越是大厂,越看重的是你的基础是否扎实,可以说基础决定了你在编码之路能走多远。不知道同学们在面试的时候有没有被问到算法,面试官会给你个逻辑算法题,让你手写,或者问一些数据结构的问题,让你给出一个较为合理的数据存储方案…那么如何充分准备关于这方面的知识,让自己在面试的时候游刃有余呢?

我们今天就来聊聊算法和数据结构,当然,由于我的个人水平有限,文中可能存在某些不太合理或者纰漏之处,望各位同学看到能不吝指出,大家一起共同进步。

程序=算法+数据结构

邹欣老师的《构建之法》里提到了一个公式:

程序 = 算法 + 数据结构

程序就是基于某种或某几种数据结构,采用某种算法或某几种算法去解决问题的过程。

我们来举个例子:去超市买菜

  1. 挑选菜品
  2. 称重
  3. 付钱
  4. 交易完成

上述例子中,是数据,“如何完成买菜” 就是这个程序的算法。在我们日常生活中其实有数不清的例子都可以用类似这样的程序来解释,只不过我们很少会有意识去思考,但其实这已经说明算法数据结构在深深影响我们的生活。

那我们拆开理解一下,什么是算法?什么是数据结构?

算法

算法的英文单词是:algorithm,这是个非常古老的概念,我国古代就有算法集《九章算术》,在数学领域,算法是解决某一类问题的公式和思想。

算法有高效的,也有低劣的。比如我们计算1+2+3+4+...+10000,如果我们一个一个算下去,那得花费多少时间?可能从天亮算到天黑都算不完。但是如果换种思路,把它拆解成下面的式子:

1 + 10000 = 10001
2 + 9999 = 10001
3 + 9998 = 10001

5000 + 5001 = 10001

也就是说1+2+3+4+...+10000有5000项 10001,提取公式就是:

(1+10000) × 10000 ÷ 2 = 5005000

怎么样,是不是对比出来很明显,后者的运行效率会高很多倍,现在很多人都知道了这个经典算法,它其实是利用了等差数列的规律,省时省力很轻松就求出了结果。

算法的好坏通常从下面2个方面来衡量:

  • 时间复杂度:指执行当前算法所消耗的时间
  • 空间复杂度:指执行当前算法需要占用多少内存空间

时间复杂度

为了计算时间复杂度,我们通常会估计算法的操作单元数量,每个单元运行的时间都是相同的。因此,总运行时间和算法的操作单元数量最多相差一个常量系数。

相同大小的不同输入值仍可能造成算法的运行时间不同,因此我们通常使用算法的最坏情况复杂度,记为T(n),定义为任何大小的输入n所需的最大运行时间。

解释一下大O:大O加上()的形式,里面其实包裹的是一个函数f(),O(f()),指明某个算法的耗时/耗空间与数据增长量之间的关系。

常见的几种算法计算类型如下:

  • 时间复杂度O(1):
    我们最常用的HashMap查询数据就是典型的O(1) 算法,无论数据量多大,都可以在一次计算后找到目标(不考虑哈希冲突的情况下)

  • 时间复杂度O(n)
    数据增大的倍数和时间增大的倍数相等,一般我们常用的遍历算法都是O(n)

  • 时间复杂度O(n²)
    例如冒泡排序需要计算n*n次,所以时间复杂度为O(n)

  • 时间复杂度O(logn)
    当数据量增大n倍,耗时增大logn倍。二分查找就是典型的O(logn)算法,每找一次排除一半的可能。

空间复杂度

算法的空间复杂度指的是占用内存、cpu等计算机资源的程度。

  • 空间复杂度 O(1)
    如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
int i = 1;
int j = 2;
int m = i + j;

上面代码中的变量分配的空间在一开始已经确定了,所以它的空间复杂度是O(1)

  • 空间复杂度O(n)
    在循环等程序结构中,如果每次循环都初始化一个新的变量,那么其空间复杂度为O(n)
for(int i = 1; i < n; i++) {
   int j = i;
}

以上,就是对算法的时间复杂度与空间复杂度基础的分析。

数据结构

分析完算法,那么我们一起再来看看数据结构。

数据结构是算法的基石,如果没有数据结构的支持,再好的算法也没用用武之地。

常用的数据结构总结如下:

数组

数组是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始,它是一种线性的数据结构。

优点:

  1. 按照索引查询元素速度快
  2. 按照索引遍历数组方便

缺点:

  1. 数组的大小固定后就无法扩容了
  2. 数组只能存储一种类型的数据
  3. 添加,删除的操作慢,因为要移动其他的元素。

适用场景:频繁查询,很少增删的情形,对存储空间的要求不大。

链表

链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域

根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。
单向链表
优点:

  1. 链表是很常用的一种数据结构,不需要初始化容量,可以任意加减元素;
  2. 添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以增删很快。

缺点:

  1. 因为含有大量的指针域,占用空间较大;
  2. 查找元素需要遍历链表来查找,非常耗时。

适用场景:数据量较小,需要频繁增加,删除操作的场景。

树是相对来说比较复杂的数据结构,其中比较有代表性的是二叉树,二叉树又衍生出了二叉堆等数据结构。

树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

树的特点:

  • 每个节点有零个或多个子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树。

二叉树是树的特殊一种,具有如下特点:

  • 每个结点最多有两颗子树,结点的度最大为2。
  • 左子树和右子树是有顺序的,次序不能颠倒。
  • 即使某结点只有一个子树,也要区分左右子树。

二叉树增删元素很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。

二叉树有很多扩展的数据结构,包括平衡二叉树、红黑树、B+树等,这些数据结构二叉树的基础上衍生了很多的功能,在实际应用中广泛用到,例如mysql的数据库索引结构用的就是B+树,还有HashMap的底层源码中用到了红黑树。如果想彻底搞懂二叉树及其衍生的数据结构,需要不断深入去研究。

散列表

散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。

Java中有些集合类就是借鉴了哈希原理构造的,例如HashMap,HashTable等,利用hash表的优势,对于集合的查找元素时非常方便的,然而,因为哈希表是基于数组衍生的数据结构,在增删元素方面是比较慢的。

堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

图是一种非常复杂的数据结构,一般被用来表示多对的的关联关系。

结尾

以上就是本期给您带来的算法 + 数据结构 简单的入门讲解,这里主要是抛砖引玉,希望同学们通过这篇文章认识到自己知识的薄弱点,有针对性的去学习和总结算法、数据结构相关的知识点。如果能在面试的时候侃侃而谈,我相信面试官肯定会对你刮目相看的。

关于算法呢,我推荐大家去leetcode网站刷题,很多大厂的算法原题都来源于此,把这里的题刷完,面试是完全没有问题的,网址:https://leetcode-cn.com/

关于数据结构,我也给大家推荐一个学习的网站:https://visualgo.net/zh

这里可以对算法进行可视化,能帮助我们非常直观地了解算法运行的过程,加深对算法和数据结构的理解。


我是程序员青戈,一个爱生活、爱分享的程序员😜

感谢您的阅读,创作不易,希望您能给我一个三连击支持我一波🤩 同时欢迎您关注我的原创公众号Java学习指南,我们可以一起吹吹牛逼、谈谈理想😆

评论 113
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员青戈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值