浅谈如何学习数据结构与算法[@初学者]

导语

所谓“数据结构”,一般来说是“数据结构与算法”,是NOIPer/NOIer、本科生、硕士生、程序员都会学的一门课程,是程序员的必修课。

数据结构为什么要学?
我们使用计算机,希望它能帮助我们解决各种各样的问题,但随着发展——
我们希望它运行得更快, 希望它能处理更多数据,希望它做一些原本不可能的事情……

计算机科学不断改变着这个世界,但代价可能是高昂的。
好的算法设计可以做得更好,而且可能很便宜;劣质的算法就不得不花费更高昂的代价。
事实上,我们可能认为提高算力就能忽略劣质算法的影响。诚然,我们也在努力提高计算机算力,但即使强如超级计算机,也无法挽救一个错误的算法。

希望很多人能正视这个问题,因为数据结构与算法真的值得学习。

学科基础

学习数据结构与算法不需要太多的基础知识,但需要你熟练掌握一门编程语言。
至少给你C/C++/Java/Python的代码你能看得懂,让你用自己熟练的编程语言能轻松实现,这样就很棒了。

至于二分查找、冒泡排序、数组之类的内容我觉得是一个刚刚入门计算机科学的孩纸就应该会的,所以就很基础,没啥可说的,该会,对吧?(比如你连冒泡排序都不会,你咋学快排啥的,对吧?)

最好有一些经验积累,我在学数据结构之前就能在一定程度上运用Java的集合框架,看过比如java.util.ArrayList啊,java.util.LinkedList这样的类的源码,其实自己写,也不过就是标准集合的低低低低低配版罢了……
(当然你只会用ArrayList我就不说啥了,好吧……)

学Java有个问题是:Java封装了指针的概念,有些人眼中看不到指针,这对理解链式结构不利。其实我觉得很好理解的,因为Java里引用在某种程度上就相当于指针了,不过是谁持有了谁的引用罢了。
暂举一个例子:

class Node<T> {
    T value;
    Node<T> next;
}

泛型啥的你想用Java就一定要会,不多说。
这里Node类的一个对象就有另一个Node对象的引用,你就可以看做一个指针啦,每一个Node都有一根线连着下一个Node,这样只需要在持有头结点,就可以构造一个简单的单链表了呢。
学的时候脑海要有联想,就要能想到指针把结点串起来成为链子。
多看看C/C++描述的图,你就能理解了,哪怕你不会……

Python数据结构……不说啥了,我也写过,总觉得不伦不类……一个数组就强爆了,啥都能干,我还写个啥子……

能用C/C++的话还是用吧……我用Java只是用着顺手+生存所迫……

哇偶差点忘了……离散数学……
离散数学应该都学过吧,树和图的基础知识在图论部分,此外其他的理论知识也很重要哇,请不要忽略离散数学哈!!!

推荐用书

我一般不太看视频,所以推荐的只有书。

  • 严蔚敏版数据结构
    在这里插入图片描述
  • 数据结构与算法分析 Java语言描述
    在这里插入图片描述
    在这里插入图片描述
  • 数据结构 Java版
    在这里插入图片描述
  • 图解数据结构
    (无图)
  • 数据结构高分笔记
    在这里插入图片描述
  • 数据结构高分笔记之习题精析扩展
    在这里插入图片描述
  • 数据结构考研复习指导
    在这里插入图片描述
  • 新编数据结构习题与解析
    在这里插入图片描述
  • ……

要学会什么

一般来说,基础数据结构与算法包含以下模块的内容:

  • Chapter 1 Introduction 数据结构导论与综述
  • Chapter 2 Array 数组、矩阵、线性表综述与顺序表
  • Chapter 3 Linked Lists 链表
  • Chapter 4 Stacks, and Queues 栈和队列
  • Chapter 5 Recursion 递归
  • Chapter 6 Trees 树与森林
  • Chapter 7 Searching 查找
  • Chapter 8 Graph
  • Chapter 9 Sorting 排序
  • Chapter 10 Hashing 散列

上面的数据结构与算法学会,虽不能满足NOIer、ACMer的需要,但至少足以满足计算机专业的本科生(包括考研考生)的知识体系了。

但这不是我想说的,在我看来,思想、方法和思维方式本身远远重要于知识和技能

学习数据结构与算法的过程中,我们要学会衡量数据结构与算法的有效性和高效性。
不仅仅是说做个题,算个O(logN),算个O(N2)什么的,我们要在写一个算法的时候下意识的能估测其算法复杂度,并学会优化算法。
我们也要尝试着去证明一些算法复杂度,比如证明斐波那契数列递归实现的算法复杂度能达到O(N5/3)

学习数据结构能引导我们进一步认识折中(Trade Off)的思想,加强与每个数据结构相关的成本和收益的概念。
说到折中这个词,这个词是软件工程、计算机科学里的重要概念,也是我很喜欢的一个词。
因为在一个计算机系统特别是一个工程化的系统中,我们可能有一系列的评估指标,我们直观地会认为,多多益善嘛,好就一定要全面,其实不然。
所谓“有得必有失”,正如同“时间换空间”、“空间换时间”等等,无论是数据结构与算法、计算机体系结构、操作系统、计算机网络还是其他,我们在追求某种或某些种更有价值(我们更需要)的“指标”的时候,总会一定程度上牺牲某些种“指标”。但相比较而言,有些东西不是我们关注的核心,那只能有“忍痛割爱”的决断了。
记得看大佬们写的东西里有这么说的:优秀的人善于做“加减法”。以我愚见,在一个计算机系统里做好“加减法”,做好取舍,追求某些方面的极致是很重要的,这是一个优秀工程师必备的素养。

怎么学

我觉得数据结构这些内容呢,说简单也简单说复杂也复杂,因人而异,因认知水平而异。

比如有的ACM大佬,就在初中就早就自己打线段树啥的了,人家完全不care你这些链表、二叉树,早就会了……

比如有的人在大学学习,还担心挂科,也不全身心投入,就觉得很难,难于上青天……

再比如有的人见识短浅,只会应付考试,整天照着课件和破书死抠,觉得自己是个什么什么东西,但自己手写一个就不会写……

形形色色的人也见过,我想提一些自己的看法,不奢求苟同。

数据结构涉及一些算法分析的内容,一定要好好体会,虽说可能对初学者难一些,但你不去尝试怎知会不会呢?
分析算法的复杂度,会证明一些东西,就很好啊。

数据结构的理论性很强,离散数学的树啊,图啊你学会了吗?是不是应该好好复习复习呢?

数据结构涉及一些算法,你会去尝试编写一些简单的算法题吗?
难道要等到机试的时候才翻白眼吗?

数据结构涉及的内容你都能熟练地掌握吗?让你写哈夫曼树的构建过程你能一步一步写出来吗?AVL树的每次调整呢?Prim算法的每一步呢?……
基础知识呢,还是要掌握的,有些考试机器就是会这种东西啊,对吧……

数据结构是有实践性的,之前说了,那你能自己手写出来(哪怕是看着参考资料但不照抄)吗?
有些人哪怕是一个链栈都写半天,学起来能不难受吗?

说到这里就想起了课设,蛮有意思的。我们那会儿写一个课设,具体内容不能透露,反正要写什么树的实际应用,要写快排,把好多同学写“哭了”。还有人啥也不会,都没了解过HashMap,还为了拿高分,抄CSDN上的HashMap。更有人狠啊,直接Copy一下Java的源码,改巴改巴用上去……
显然,有些人运气好些,大部分人分数不高,何必呢?学习难道就是为了考个试?还是为了混个时间呢?

上面大多用了问句,希望能引起读者的自我反思与自我警醒吧。

另外分享一则我的教训,我当时在学课程的时候由于忙着做一个项目还有学别的,加上学校开课只开8个周,时间紧迫。好在我早有准备,不仅看过书、编程实现过,甚至看过Java集合框架的源码,就学起来很简单,利用上课时间就轻松掌握了。但准备考试的时候时间根本没有,自己之前也没腾时间出来耐心复习,甚至基本说是“裸考”,最后很遗憾才得了90多分,不高。所以希望大家自己注意,如果是在校学习,一定要留足时间复习,争取满分。奥利给!!
在这里插入图片描述

列个C++版学习路线图

Part1

  • 数据结构研究的问题
  • 什么是数据、数据结构及常用的数据结构
  • 抽象数据类型及面向对象概念
  • 数据结构的抽象层次
  • 用C++描述面向对象程序
  • 算法定义、特征和算法的性能标准
  • 模板
  • 性能分析与度量(学会度量)
  • 动态存储分配
  • 深复制和浅复制
  • 模板
  • 继承
  • 异常处理
  • 设计模式
  • STL及STL的构成

Part2

  • 数组的概念和抽象数据类型定义
  • 数组的顺序存取方式,数组元素存储地址的计算
  • 顺序表的概念及抽象数据类型定义
  • 顺序表的基本操作:存取、插入、删除、查找、求前驱、后继等相关操作、时间复杂度分析
  • 多项式抽象数据类型及二种存储表示和加法运算
  • 特殊矩阵(三角阵、对称阵、带状阵)的压缩存储
  • 稀疏矩阵的定义、压缩存储;稀疏矩阵的转置运算算法
  • 字符串的定义及抽象数据类型
  • 串的存储和主要运算
  • STL内容( string, vector, deque)

Part3

  • 单链表的类定义
  • 链表结点(ListNode)类, 链表(List)类, 链表游标(Iterator)类
  • 单链表的插入和删除(链表头、链表中间、链表尾)
  • 带表头结点的单链表的实现
  • 链表的游标类Iterator实现
  • 静态链表,循环链表,双向链表的实现
  • 稀疏矩阵的十字链表表示法
  • 链表实现多项式相加

Part4

  • 栈的概念和抽象数据类型定义。栈操作特点
  • 术语:栈顶、栈底、队头、队尾、上溢、下溢
  • 栈的顺序和链式实现
  • 栈的主要运算: 进栈操作 ,出栈操作, 取栈顶元素。
  • 队列的概念和抽象数据类型定义。队列操作特点。
  • 队列的顺序(循环队列)和链式实现方法。
  • 队列的主要运算:入队列、出队列。
  • 优先级队列
  • STL中队列和栈的类型
  • stack和queue的使用方法

Part5

  • 递归的概念
  • 递归与递归工作栈
  • 利用栈的迷宫非递归解决方案
  • 广义表的概念
  • 术语:表长、空表、表的深度、表头、表尾
  • 学会计算表头、表尾
  • 广义表存储结构及其实现

Part6

  • 树的定义、树的基本概念术语,抽象数据类型
  • 二叉树定义、性质、抽象数据类型,满二叉树,完全二叉树
  • 二叉树的存储结构:顺序存储、链式存储结构
  • 二叉树类定义,二叉树基本操作
  • 遍历二叉树:按深度遍历(前序、中序、后序)、递归和非递归算法;按层次遍历。
  • 二叉树遍历的游标类
  • 线索二叉树:定义、添加线索
  • 堆的定义及抽象数据类型
  • 堆的建立(如何调整成堆)、堆的插入
  • 树的存储结构:广义表表示、双亲表示法、左子女-右兄弟表示。
  • 森林与二叉树的转换
  • 树和森林的遍历
  • 哈夫曼树及应用
  • set,map,priority_queue

Part7

  • 搜索的定义、搜索表、关键字、ASL
  • 静态搜索表的搜索:顺序搜索、二分法搜索。复杂度分析
  • 二叉搜索树的类定义、搜索的实现、插入的实现、删除的实现
  • 二叉搜索树游标类的定义
  • AVL树定义、平衡因子、平衡化旋转(学会调整的方法)

Part8

  • 图的概念和术语、抽象数据类型
  • 图的存储结构:邻接矩阵、邻接表及其实现方法
  • 图的遍历:深度优先、广度优先。
  • 生成树和最小生成树:概念、算法(Prim、Kruskal算法)。
  • 求有向网的一个顶点到其余所有顶点的最短路径的算法(迪杰斯特拉算法)。
  • 有向无环图:AOV网和AOE网概念、拓扑序列、拓扑排序及算法、关键路径和关键活动的概念、关键活动和关键路径的求解方法。

Part9

  • 排序的定义、关键码、内排序/外排序、稳定性
  • 插入排序:直接插入排序、二分法插入排序、希尔排序
  • 选择排序:直接选择排序、堆排序
  • 交换排序:冒泡排序、快速排序
  • 归并排序:(二路)归并排序
  • 各种排序方法的比较与选择

Part10

  • 静态索引结构:线性索引的搜索过程及效率、 m路静态搜索树
  • 动态索引结构
  • B-树的定义、查找、插入、删除过程
  • 散列表相关概念:散列、散列函数、散列表、同义词、冲突、装填因子(负载因子)
  • 常用的散列函数和两种解决冲突的方法(线性探查法、链地址法)
  • 散列表的查找及ASL

Java版学习路线图

其实类似的啊,就把Java基础弄会就好啦。
最最基本的是你要会基础知识、数组、基础类库、面向对象程序设计、泛型这些。
数组是你一定会一直用的,因为你不可能再给ArrayList封装一层,所以要你自己写。
Java作为纯粹面向对象的语言,你不会面向对象就相当于废了。而且数据结构都要封装成类来实现的。
泛型的话,你写的LinkedList不可能只装int啊,毕竟你也不用会的那么深。

别的自然是多多益善,迭代器、比较器啥的其实也可以自己写啊……

疯狂安利

这里是我整理的一个数据结构与算法大全,主要是Java,也有Python和JavaScript语言的一些数据结构实现,更是有一些笔记和感悟,希望对读者有帮助 → Here

有问题可探讨,不喜勿喷,感谢Orz……

既然看到这里……如果有帮助……是不是应该点个赞再走呢?毕竟我也是讲了掏心窝子的话是吧……
OrzOrzOrzOrz
在这里插入图片描述在这里插入图片描述在这里插入图片描述

Bye~ Bye~
在这里插入图片描述

发布了479 篇原创文章 · 获赞 972 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104193739