❤️三万字《算法和数据结构》数据结构到底有多重要,写给还在上大学的你❤️(建议收藏)
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❤️三万字《算法和数据结构》数据结构到底有多重要,写给还在上大学的你❤️(建议收藏)相关的知识,希望对你有一定的参考价值。
直接跳到末尾 获取粉丝专属福利。
零、前言
「 数据结构 」 和 「 算法 」 是密不可分的,两者往往是「 相辅相成 」的存在,所以,在学习 「 数据结构 」 的过程中,不免会遇到各种「 算法 」。
到底是先学 数据结构 ,还是先学 算法,我认为不必纠结这个问题,一定是一起学的。
数据结构 常用的操作一般为:「 增 」「 删 」「 改 」「 查 」。基本上所有的数据结构都是围绕这几个操作进行展开的。
那么这篇文章,作者将主要来聊聊:
「 算法和数据结构 」
在学习数据结构的过程中,如果你能够自己把图画出来,并且能够描述整个 「 增 」 「 删 」 「 改 」 「 查 」 的过程,那么说明你已经真正理解了数据结构的真谛,来看下下面几张图:
文章目录
一、算法和数据结构的重要性
1、为什么要学习算法
如果你只是想学会写代码,或许 「 算法与数据结构 」 并不是那么重要,但是,想要进一步发展自己的事业,「 算法与数据结构 」 是必不可少的。
现在一些主流的大厂,诸如:字节、网易、腾讯、阿里、美团、京东、滴滴 等等,在面时都会让候选人写一道 「 算法题 」 ,如果你敲不出来,可能你的 offer 年包就打了骨折,或者直接与 offer 失之交臂,都是有可能的。
当然,它不能完全代表你的编码能力(因为有些算法确实是很巧妙,加上紧张的面试氛围,想不出来其实也是正常的),但是你能确保面试官是这么想的吗?我们要做的是十足的准备,既然决定出来,offer 当然是越高越好,毕竟大家都要养家糊口,房价又这么贵,如果能够在算法这一块取得先机,也不失为一个捷径。
所以,你问我算法和数据结构有什么用?我可以很明确的说,和你的年薪息息相关。当然,面试中 「算法与数据结构」 知识的考察只是面试内容的一部分。其它还有很多面试要考察的内容,当然不是本文主要核心内容,这里就不做展开了。
2、如何有效的学习
这篇文章中,我会着重讲解一些常见的 「 算法和数据结构 」 的设计思想,并且配上动图。主要针对面试中常见的问题和新手朋友们比较难理解的点进行解析。当然,后面也会给出面向算法竞赛的提纲,如果有兴趣深入学习的欢迎在评论区留言,一起成长交流。
零基础学算法的最好方法,莫过于 「 刷题 」 了。任何事情都是需要 「 坚持 」 的,刷题也一样,没有刷够足够的题,就很难做出系统性的总结。所以上大学的时候,我花了三年的时间来刷题, 工作以后还是会抽点时间出来刷题。
当然,每天不需要花太多时间在这个上面,把这个事情做成一个 「 规划 」 ,按照长期去推进。反正也没有 KPI 压力,就当成是工作之余的一种消遣,还能够提升思维能力。所谓: 「 十年磨一剑,今朝把示君 」 。
3、坚持并且把它当成兴趣
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
如果你满足如下:
(
1
)
(1)
(1) 有强烈欲望「 想要学好C语言 」的人
(
2
)
(2)
(2) 有强烈欲望「 想要学好C++ 」的人
(
3
)
(3)
(3) 有强烈欲望「 想要学好数据结构 」的人
(
4
)
(4)
(4) 有强烈欲望「 想学好算法 」的人
(
5
)
(5)
(5) 有强烈欲望「 想进大厂 」的人
如果你满足以上任意一点,那么,我们就是志同道合的人啦!
🔥联系作者,或者扫作者主页二维码加群,加入我们吧🔥
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
如果链接被屏蔽,或者有权限问题,可以私聊作者解决。
大致题集一览:
为了让这件事情变得有趣,以及 「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括: 线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为 「 夜深人静写算法 」专家团 的一员。
不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上, 「 不会索取任何东西 」,也不会产生任何利益输送。
4、首先要有语言基础
那么在进行算法学习之前,我们需要实际落地,就需要有一门语言基础,可以是 C语言、Java、Python 中的任意一种。当然,作者推荐的是 C语言。可以在作者的专栏中找到学习方法。
学习的过程中,也要适当进行联系,可以看下如下专栏:
这个专栏是作者经过收集了个各种简单的C语言题库编撰而成,基本包含了 C语言的大部分语法。并且,加入了一些入门级别的算法题,适合刚涉足这块领域的同学。
5、如何开始学习数据结构
学习数据结构之前,选择一款相对来说心仪的教程是必不可少的,我这里准备了一个用动画来解释数据结构的教程,在我这也有,就是:
这是我目前来说,写的最用心的一个教程,里面汇集了大量的动图,目前更新已经过半,好评如潮。
当然,一边学习,一边做一些练习题是必不可少的,接下来就是推荐一个我自己整理的题集了,这个题集汇集了大量的算法。可以帮你在前行的路上扫平不少障碍。
在看上述题目时,如果遇到难以解决的问题,可以参考如下解题报告专栏:
6、数据结构和算法是相辅相成的
如果你在刷题的过程中,已经爱上了算法,那么恭喜你,你将会无法自拔,一直刷题一直爽,在遇到一些高端的算法时,也不要惊慌,这里推荐一个竞赛选手金典图文教程,如下:
二、数据结构是根基
学习算法,数据结构是根基,没有一些数据结构做支撑,这个算法都没有落脚点,任何一个简单的算法都是需要数据结构来支撑的,比如最简单的算法,
1、数组
内存结构:内存空间连续
实现难度:简单
下标访问:支持
分类:静态数组、动态数组
插入时间复杂度: O ( n ) O(n) O(n)
查找时间复杂度: O ( n ) O(n) O(n)
删除时间复杂度: O ( n ) O(n) O(n)
一、概念
1、顺序存储
顺序存储结构,是指用一段地址连续的存储单元依次存储线性表的数据元素。
2、存储方式
在编程语言中,用一维数组来实现顺序存储结构,在C语言中,把第一个数据元素存储到下标为 0 的位置中,把第 2 个数据元素存储到下标为 1 的位置中,以此类推。
3、长度和容量
数组的长度指的是数组当前有多少个元素,数组的容量指的是数组最大能够存放多少个元素。如果数组元素大于最大能存储的范围,在程序上是不允许的,可能会产生意想不到的问题,实现上是需要规避的。
如上图所示,数组的长度为 5,即红色部分;容量为 8,即红色 加 蓝色部分。
4、数据结构定义
#define MAXN 1024
#define DataType int // (1)
struct SeqList {
DataType data[MAXN]; // (2)
int length; // (3)
};
-
(
1
)
(1)
(1) 数组类型为
DataType
,定义为int
; -
(
2
)
(2)
(2)
SeqList
定义的就是一个最多存放MAXN
个元素的数组,MAXN
代表数组容量; -
(
3
)
(3)
(3)
length
代表数组长度,即当前的元素个数。
二、常用接口实现
1、索引
索引 就是通过 数组下标 寻找 数组元素 的过程。C语言实现如下:
DataType SeqListIndex(struct SeqList *sq, int i) {
return sq->data[i]; // (1)
}
- ( 1 ) (1) (1) 调用方需要注意 i i i 的取值必须为非负整数,且小于数组最大长度。否则有可能导致异常,引发崩溃。
- 索引的算法时间复杂度为
O
(
1
)
O(1)
O(1)。
2、查找
查找 就是通过 数组元素 寻找 数组下标 的过程,是索引的逆过程。
对于有序数组,可以采用 二分 进行查找,时间复杂度为
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n);对于无序数组,只能通过遍历比较,由于元素可能不在数组中,可能遍历全表,所以查找的最坏时间复杂度为
O
(
n
)
O(n)
O(n)。
简单介绍一个线性查找的例子,实现如下:
DataType SeqListFind(struct SeqList *sq, DataType dt) {
int i;
for(i = 0; i < sq->length; ++i) { // (1)
if(sq->data[i] == dt) {
return i; // (2)
}
}
return -1; // (3)
}
- ( 1 ) (1) (1) 遍历数组元素;
- ( 2 ) (2) (2) 对数组元素 和 传入的数据进行判等,一旦发现相等就返回对应数据的下标;
-
(
3
)
(3)
(3) 当数组遍历完还是找不到,说明这个数据肯定是不存在的,直接返回
−
1
-1
−1。
3、获取长度
获取 数组的长度 指的是查询当前有多少元素。可以直接用结构体的内部变量。C语言代码实现如下:
DataType SeqListGetLength(struct SeqList *sq) {
return sq->length;
}
4、插入
插入接口定义为:在数组的第 k k k 个元素前插入一个数 v v v。由于数组是连续存储的,那么从 k k k 个元素往后的元素都必须往后移动一位,当 k = 0 k=0 k=0 时,所有元素都必须移动,所以最坏时间复杂度为 O ( n ) O(n) O(n)。C语言代码实现如下:
int SeqListInsert(struct SeqList *sq, int k, DataType v) {
int i;
if(sq->length == MAXN) {
return 0; // (1)
}
for(i = sq->length; i > k; --i) {
sq->data[i] = sq->data[i-1]; // (2)
}
sq->data[k] = v; // (3)
sq->length ++; // (4)
return 1; // (5)
}
- ( 1 ) (1) (1) 当元素个数已满时,返回 0 0 0 代表插入失败;
- ( 2 ) (2) (2) 从第 k k k 个数开始,每个数往后移动一个位置,注意必须逆序;
- ( 3 ) (3) (3) 将第 k k k 个数变成 v v v;
- ( 4 ) (4) (4) 插入了一个数,数组长度加一;
- ( 5 ) (5) (5) 返回 1 1 1 代表插入成功;
5、删除
插入接口定义为:将数组的第 k k k 个元素删除。由于数组是连续存储的,那么第 k k k 个元素删除,往后的元素势必要往前移动一位,当 k = 0 k=0 k=0 时,所有元素都必须移动,所以最坏时间复杂度为 O ( n ) O(n) O(n)。C语言代码实现如下:
int SeqListDelete(struct SeqList *sq, int k) {
int i;
if(sq->length == 0) {
return 0; // (1)
}
for(i = k; i < sq->length - 1; ++i) {
sq->data[i] = sq->data[i+1]; // (2)
}
sq->length --; // (3)
return 1; // (4)
}
- ( 1 ) (1) (1) 返回0代表删除失败;
- ( 2 ) (2) (2) 从前往后;
- ( 3 ) (3) (3) 数组长度减一;
- ( 4 ) (4) (4) 返回1代表删除成功;
- 想要了解更多数组相关内容,可以参考:《画解数据结构》(1 - 1)- 数组。
2、链表
内存结构:内存空间连续不连续,看具体实现
实现难度:一般
下标访问:不支持
分类:单向链表、双向链表、循环链表、DancingLinks
插入时间复杂度: O ( 1 ) O(1) O(1)
查找时间复杂度: O ( n ) O(n) O(n)
删除时间复杂度: O ( 1 ) O(1) O(1)
一、概念
- 对于顺序存储的结构,如数组,最大的缺点就是:插入 和 删除 的时候需要移动大量的元素。所以,基于前人的智慧,他们发明了链表。
1、链表定义
链表 是由一个个 结点 组成,每个 结点 之间通过 链接关系 串联起来,每个 结点 都有一个 后继节点,最后一个 结点 的 后继结点 为 空结点。如下图所示:
- 由链接关系
A -> B
组织起来的两个结点,B
被称为A
的后继结点,A
被称为B
的前驱结点。 - 链表 分为 单向链表、双向链表、循环链表 等等,本文要介绍的链表是 单向链表。
- 由于链表是由一个个 结点 组成,所以我们先来看下 结点 的实现。
2、结点结构体定义
typedef int DataType;
struct ListNode {
DataType data; // (1)
ListNode *next; // (2)
};
-
(
1
)
(1)
(1) 数据域:可以是任意类型,由编码的人自行指定;这段代码中,利用
typedef
将它和int
同名,本文的 数据域 也会全部采用int
类型进行讲解; - ( 2 ) (2) (2) 指针域:指向 后继结点 的地址;
- 一个结点包含的两部分如下图所示:
3、结点的创建
- 我们通过 C语言 中的库函数
malloc
来创建一个 链表结点,然后对 数据域 和 指针域 进行赋值,代码实现如下:
ListNode *ListCreateNode(DataType data) {
ListNode *node = (ListNode *) malloc ( sizeof(ListNode) ); // (1)
node->data = data; // (2)
node->next = NULL; // (3)
return node; // (4)
}
-
(
1
)
(1)
(1) 利用系统库函数
malloc
分配一块内存空间,用来存放ListNode
即链表结点对象; -
(
2
)
(2)
(2) 将 数据域 置为函数传参
data
; - ( 3 ) (3) (3) 将 指针域 置空,代表这是一个孤立的 链表结点;
-
(
4
)
(4)
<
以上是关于❤️三万字《算法和数据结构》数据结构到底有多重要,写给还在上大学的你❤️(建议收藏)的主要内容,如果未能解决你的问题,请参考以下文章
❤️三万字详解《十大入门算法》突击刷掉这几个题,面试不慌!❤️(附源码,建议收藏)
❤️ 爆肝三万字《数据仓库体系》轻松拿下字节offer ❤️建议收藏