尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

数据结构绪论与算法分析:从三要素到大O记号的学习框架

数据结构绪论与算法分析:从三要素到大O记号的学习框架 很多人在数据结构这门课上栽的第一个跟头不在链表也不在二叉树而在绪论。原因很简单绪论里全是数据元素逻辑结构时间复杂度这类抽象名词乍看像背诵题实际却是整门课的框架。我见过不少同学跳过绪论直接刷题学到树和图时才发现复杂度分析不会推、存储结构选型全靠猜回头补课的成本远高于一开始就花两三天把绪论啃透。这篇就围绕数据结构绪论和算法分析把为什么学、学什么、怎么用拆开讲清楚既适合期末复习和考研初期的同学建立框架也适合自学者完整体会这门课的设计逻辑。1. 绪论到底在讲什么从背概念到搭框架1.1 数据、数据元素、数据项三个概念决定你建模的粒度先说最基础的一组概念。数据是能输入计算机并被处理的符号集合数字、文字、图像、音频都是数据。数据元素是数据的基本单位通常由若干数据项组成数据项是构成数据元素的不可分割的最小单位。听起来绕实际举个例子就通了。假设你要写一个学生信息管理系统整个学生名册就是数据集合其中每一个学生的完整记录学号、姓名、成绩就是一个数据元素而学号姓名成绩各自就是数据项。在设计数据结构时你首先要想清楚的其实是粒度问题程序里以什么为单位进行存储和操作是整条学生记录还是只拿学号这决定了你后面定义的结构长什么样。这个区分在考研选择题里经常以判断哪个是数据元素/数据项的形式出现。考法本身不难但它背后是一个建模思维现实世界里的事物落在计算机里必须先做一个抽象成符号、再划分成个体、再拆出最小字段的过程。很多人在后面学图论时觉得顶点边抽象到头秃根源就是在绪论阶段没有养成这种建模感。1.2 逻辑结构、存储结构、运算三要素才是真正的核心数据结构这门课定义过无数遍但最值得记住的是这句话数据结构是相互之间存在一种或多种特定关系的数据元素的集合。这句定义的关键词是关系它引出了学习全书的三个抓手逻辑结构数据元素之间的抽象关系包括集合、线性结构、树形结构、图状结构。存储结构逻辑结构在计算机存储器中的表示包括顺序存储、链式存储、索引存储、散列存储。数据的运算定义在逻辑结构上的操作比如插入、删除、查找、排序具体实现依赖存储结构。这三者的关系我用一句话概括逻辑结构是你要什么关系存储结构是你用什么方式把这些关系落到内存里运算是你拿着这套结构能干什么。举一个具体场景。你要管理一个通讯录联系人之间的关系就是一条线性的先后顺序——这就确定了逻辑结构是线性表。实现这条线性表可以用一段连续的内存挨个存放联系人顺序存储也可以用每个联系人带一个指向下一位的指针链式存储。不管底层是哪种存法新增一个联系人按名字查找这些运算的目标是一样的但实现效率大不相同。所以学后面的顺序表、链表、栈、队列、树、图时头脑里始终要有这个三要素框架每遇到一个数据结构先问它是哪种逻辑结构再问它的各种实现对应什么存储结构最后问每种运算在特定存储结构下怎么实现、复杂度多少。这个习惯一旦建立后面所有章节都会变得很有秩序。1.3 用租房类比帮助建立直觉如果觉得概念还是飘可以用一个生活化类比逻辑结构是房子的户型图几室几厅、朝向、动线存储结构是这套房子的实际装修方式墙体怎么砌、家具怎么摆运算就是你在这个房子里完成的各种活动做饭、睡觉、会客。同一个户型图可以装成北欧风也可以装成中式风这是存储结构的选择空间但不管怎么装修卧室的功能还是睡觉这是运算的确定性。类似的同样的线性表逻辑结构可以用顺序表实现也可以用链表实现用户层面看到的插入一个元素语义是一样的实现的代价却完全不同。把这三层关系刻进脑子里绪论的骨架就立住了。2. 存储结构这关怎么过顺序、链式、索引、散列的取舍逻辑2.1 顺序存储连续内存的二房东逻辑顺序存储的核心是把逻辑上相邻的元素放到物理地址也相邻的存储单元里。数组是它最典型的代表。它最大的优点是随机访问只要知道首地址和下标一步就能算出目标元素的位置所以按位置取值的时间复杂度是O(1)就像你知道这栋楼的房间号按门牌走过去就行。但它的代价也很明显插入和删除通常要移动大量元素来维持物理相邻这个性质。比如在数组中间插入一个元素后面的所有元素都要往后挪一位最坏情况下是O(n)。所以顺序存储的取舍是以移动换访问——访问极快写操作插入/删除慢。在绪论阶段最容易被忽略的是动态顺序存储的概念。现实中没人一开始就知道数据规模于是出现了动态数组比如C的vector、Python的list底层还是一块连续内存装不下了就申请一块更大的把旧数据复制过去。这个扩容操作单次是O(n)但均摊下来每次追加还是常数级。这个均摊分析是算法分析的进阶话题但在绪论里提前建立印象会很有好处。2.2 链式存储用指针换灵活性的自由改造链式存储不复用地址连续性每个节点除了存数据还要存指向下一个节点的指针甚至指向前驱的指针就变成双向链表。它最大的好处是插入删除不用搬数据只要改相邻节点的指针指向时间复杂度是O(1)前提是已经定位到目标节点。但代价是按位置找第k个元素时必须从头指针一个个走最坏是O(n)也就是失去随机访问能力同时每个节点多存了指针内存开销变大。此外链式存储天然解决了数据规模不确定的问题——需要用多少节点就开多少动态性比静态数组好得多。我在实际带项目时有个体会很多人一听到链表插入O(1)就激动但别忘了你要先花O(n)找到插入位置才有后面的O(1)。换句话说只有在已经持有目标节点指针的场景比如在已知节点后面插入链式存储才真正体现优势。这提醒我们复杂度结论必须看完整操作链不能只捡好听的那一段。2.3 索引存储与散列存储另两条路线索引存储是多加一层目录的思路数据主体用一个区比如按块存放另外建一个索引表记下每个块的关键字和存储地址。查数据时先查索引定位到块再进块里找。这几乎是数据库的通用套路也是操作系统中文件系统的经典组织方式。它本质上是在顺序存储和动态需求之间做折中——主体连续存放节省空间索引层提供快速定位。散列存储走的是完全不同的路通过一个散列函数把元素的关键字直接映射成存储地址。理想情况下你给出关键字一次计算就能拿到位置这是O(1)级别的查找。但散列有冲突问题——两个关键字可能算出同一个地址于是有开放定址、链地址法等一堆处理手段。这些细节后面章节会展开但绪论阶段你只要记住它追求的是用计算换定位。选择哪种存储结构本质上是在访问速度、插入删除成本、空间开销、实现复杂度之间做权衡。这里给一个简单的决策思路场景特征优先考虑的存储结构原因频繁按位置访问、基本不插入删除顺序存储随机访问O(1)频繁插入/删除、不常按下标访问链式存储改指针完成插入删除数据量大、需要先定位块再读取索引存储目录定位减少扫描范围按关键字精确匹配、要求极快查找散列存储一次散列计算定位数据规模不确定、需要灵活伸缩链式/动态顺序空间按需分配这个表格值得抄进笔记本。后面每学一种具体数据结构都可以回到这张表来校验它选择了什么存储结构为什么要这样选付出了什么代价。如果只是记住顺序表查询快、链表插入快这种碎片结论做起综合题来很容易掉进陷阱。2.4 出圈一点工程领域里数据结构同样无处不在有搜索热词提到pandas数据结构创建这正好可以说明数据结构不是考研专属的抽象概念。在我们日常用的数据分析库里Series和DataFrame本质上也是结构化的数据组织方式——它们内部依托NumPy数组本质是顺序存储加上索引机制实现按标签快速访问。你在里面对一个DataFrame做筛选、合并、重塑本质上都是对某种数据结构执行运算。我提这个是想说绪论里学的这些模式并不只在408考卷上出现。无论你以后做业务系统、数据分析还是算法岗设计的本质永远是在特定约束下选择合适的数据组织方式和运算策略。有了这层视角绪论就不再是八股而是真正做事的方法论。3. 抽象数据类型ADT把操作也变成规范3.1 为什么需要ADT先定义能干什么再想怎么实现抽象数据类型ADTAbstract Data Type是绪论里另一个极容易被低估的概念。它的定义是一个数学模型以及定义在该模型上的一组操作。注意ADT强调的是定义操作不含具体实现。也就是说你先把这个数据结构对外提供什么能力约定清楚至于底层是用数组还是链表、用连续内存还是指针那是实现层的事。为什么要这样分层想象一台自动贩卖机你投币、按编号、取饮料这就是它对外提供的操作至于内部是履带传送还是弹簧推出你完全不关心。把界面和实现分开带来两个巨大好处第一使用方只需依赖稳定的操作接口不因内部实现变化而重写代码第二实现方可以自由替换更高效的内部方案只要保持对外行为不变。这个思想往后贯穿整个计算机体系。你在系统设计里说的面向接口编程、在工程里说的封装变化源头都可以追溯到ADT的概念。很多教材把ADT讲得太薄学生就误以为它只是个定义格式其实它是组件化思维的起点。3.2 一个完整ADT长什么样以线性表为例以线性表为例一个标准的ADT定义通常包含三部分数据对象、数据关系、基本操作。写出来大致是这样数据对象D {a₁, a₂, ..., aₙ | n ≥ 0}n是表长每个aᵢ是数据元素。数据关系R {aᵢ₋₁, aᵢ | i 2, 3, ..., n}即元素之间是一对一的线性关系。基本操作InitList(L)、ListInsert(L, i, e)、ListDelete(L, i, e)、GetElem(L, i)、LocateElem(L, e)等等。注意定义里的符号表示引用型参数意思是这个操作会修改实参本身。考研里常考的一个点就是区分哪些操作会改变表要传引用哪些操作只读不写直接传值。这个细节不只是应试它反映的是操作对外部状态的影响范围——在设计API时你得明确告诉调用方这个调用会不会改动你的数据。3.3 从ADT到具体实现同一种逻辑结构多种存储方案有了ADT之后同一个逻辑结构就能对应多个具体实现。同样是线性表这个ADT你可以用顺序存储实现成顺序表也可以用链式存储实现成单链表、双向链表、循环链表。对外来看它们都支持在第i个位置插入元素这个操作对内来看顺序表的插入要移动元素链表的插入要改指针。这正是很多期末考题的命题点给出一个具体的操作序列要你分别分析在顺序表和单链表上的时间复杂度。结论往往不一样。理解了ADT的分层思想你就会明白复杂度差异不是操作语义造成的而是底层实现策略造成的。很多人到这一步会困惑同一个插入怎么一会儿O(1)一会儿O(n)本质是没分清ADT层和实现层。我自己的学习体会是每学完一个数据结构的ADT定义先自己用自然语言写一遍它支持的操作清单再在纸上画一画顺序实现和链式实现的差别。这个动作只需要半小时但对后续理解栈、队列、串、广义表都有迁移作用因为它们的ADT骨架一模一样只是数据关系和操作集合不同。4. 时间复杂度用增长趋势说话用大O记号写结论4.1 算法的五个特性为什么有穷性排在第一位进入算法分析之前教材通常会先给算法的定义和特性有穷性、确定性、可行性、输入、输出。这里很多人只是背了名词但没有真正理解为什么这五条能筛掉不是算法的东西。有穷性说的是算法必须在有限步骤后结束这直接把死循环排除在外确定性是说每条指令都无歧义同一个输入走法唯一可行性是说操作能通过有限次基本运算完成不能定义直接得出答案这种作弊式步骤输入和输出则规定了算法的边界——它可以没有输入但一定要有输出否则跑了半天没有结果别人无法使用。这五条不是八股而是给什么是可计算过程划了一条清晰的线。在描述一个算法时我会习惯性地拿这五条快速自检一遍特别是有穷性。有些递归实现看起来很美但实际上递归深度无限增长最后不在有限步内停止——这就是一个有穷性不满足的伪算法。4.2 为什么不拿秒表计时机器无关性的需求评价算法效率最直觉的思路是跑一遍看用了多少秒。这个方法在工程里当然有用但在算法分析层面有一个致命缺陷结果严重依赖机器性能、编程语言、编译器优化、当前系统负载。同一段冒泡排序在i9上可能比在至强E3上快好几倍但算法本身的优劣并没有变。于是需要一种与机器无关、只与数据规模n相关的度量方式。这就是时间复杂度的出发点把基本运算的执行次数表示成关于问题规模n的函数T(n)然后研究n增长时T(n)的增长趋势。注意基本运算是指算法中执行次数最多、起主导作用的语句通常是循环体的核心操作。举个例子一个单层循环从1跑到n里面一条赋值语句那基本运算执行次数就是n次严格说是约n次因为循环变量初始化和判断条件也有开销但那是常数级别不影响趋势T(n) n增长趋势是线性的。4.3 大O记号的直觉抛掉系数和低阶项只看增长等级大O记号是复杂度分析的核心工具。它的形式化定义是用极限和存在常数来描述的但直觉上很简单当n足够大时T(n)的量级不超过某个倍数f(n)就记作T(n) O(f(n))。我们真正关心的是增长率而不是具体数值。这就是为什么复杂度分析里常数系数不重要2n和100n都是O(n)n²3n1是O(n²)。当n取到一万、十万时主导增长的是最高阶项低阶项和系数都决定不了曲线的走向。用生活类比就是看一个人十年后的财富量级是看他的收入模式打工、创业、投资还是看他现在账上多三五千块当然是模式。大O描述的就是模式不是余额。常见复杂度量级从优到劣排下来大概是O(1)常数时间比如数组按下标访问。O(log n)对数时间比如二分查找。O(n)线性时间比如单遍扫描。O(n log n)线性对数时间比如归并排序、快速排序平均。O(n²)平方时间比如冒泡排序、简单双层循环。O(2ⁿ)指数时间比如朴素递归求斐波那契。O(n!)阶乘时间比如全排列暴力枚举。你不需要急着把它们全展开但你一定要建立n的规模变化时这些量级的差距有多大的直觉。同样是n100O(logn)的算法大概执行几十次O(n)是一百次O(n²)是一万次O(2ⁿ)直接爆掉。这也是为什么复杂度分析不是考试专用——它决定了你的程序在真实数据量下是秒回还是等死。4.4 最坏、平均、最好分别什么时候用一个算法在不同输入下的执行时间可能差异巨大。以顺序查找为例目标是数组第一个元素一次就找到最好时间复杂度O(1)目标是最后一个或者不存在扫描完整个数组最坏O(n)综合起来平均也是O(n)量级。这三个指标里最坏时间复杂度是最重要的。原因很简单在真实系统中你无法保证输入恰好是最好情况而最坏情况往往决定了系统能不能扛住极端流量。做工程时我会优先保证算法的最坏情况可接受再去想平均场景的优化。平均时间复杂度的分析相对复杂因为它需要知道输入的概率分布而最好时间在绝大多数情况下只是锦上添花。考研题里常混淆的考点是有人说快速排序最好的时间复杂度是O(nlogn)、最坏是O(n²)这里说的就是同一算法在不同输入分布下的表现差异。理解复杂度是输入的函数这一点是看穿此类题的钥匙。5. 从代码到大O复杂度计算的完整实操套路5.1 三条基本功循环次数、嵌套乘法、对数步进复杂度计算看着玄其实套路很固定。给你三个基本武器第一单层循环看循环变量走多少步。for(i0; in; i)执行n次核心操作次数就是O(n)。第二嵌套循环总体相乘。外层n次内层每次都执行n次总次数n×nO(n²)。这里要注意陷阱内层循环的次数如果和外层变量有关就不能盲目相乘。比如for(i0; in; i) { for(j0; ji; j) ... }总次数是012...(n-1)n(n-1)/2仍然是O(n²)但推导过程需要用到求和公式而不是简单n×n。第三对数步进。循环变量不是每次加1而是每次乘以2或除以2比如i从1开始每次ii*2直到in那执行次数就是log₂n量级记为O(logn)。二分查找每次把搜索区间砍半就是这个模式。这里我想强调一个容易被忽略的点分析循环时真正要数的是核心操作执行的次数不是循环变量本身。有时循环体里有条件判断只有满足条件才执行关键操作那要看最坏情况触发多少次而不是循环总次数。5.2 递归的复杂度递推方程的基本解法递归的时间复杂度比循环难在一个地方——它不是显式数次数而是要用递推关系表达。比如递归求前n项和int sum(int n) { if (n 1) return 1; return n sum(n - 1); }它的执行时间T(n)可以写成T(n) T(n-1) O(1)边界是T(1) O(1)。这个方程展开来就是n次常数操作相加所以T(n) O(n)。这是线性递归的典型结果递归深度是n每层做了常数工作。再看一个更经典的例子朴素递归求斐波那契数int fib(int n) { if (n 1) return n; return fib(n - 1) fib(n - 2); }这就不一样了。T(n) T(n-1) T(n-2) O(1)解出来是指数级的O(2ⁿ)。原因很好理解每次调用产生两个子调用调用树的节点数随深度指数增长。虽然实际不是精确的2ⁿ但增长量级是指数。这也是为什么教科书反复强调朴素递归求斐波那契不是好算法——不是递归本身不好而是这个解法没有利用重叠子问题。后面学的动态规划本质就是把指数级的递归改成多项式级。考研和期末考试里递归复杂度的题主要就两种一是线性递推二是树形递推。线性递推基本对应O(n)树形递推对应O(2ⁿ)或者在对数高度下变成O(nlogn)。看到每次递归调用一个规模更小的子问题基本往O(n)想看到每次递归分裂成多个子问题就要小心可能是指数爆炸。5.3 常见排序算法的复杂度结论背后的推导逻辑然后是几乎必考的排序算法复杂度。这里不要求死背但要能从原理推出结论。我按类梳理排序算法最好时间平均时间最坏时间空间复杂度稳定性冒泡排序O(n)O(n²)O(n²)O(1)稳定简单选择排序O(n²)O(n²)O(n²)O(1)不稳定直接插入排序O(n)O(n²)O(n²)O(1)稳定希尔排序O(n)O(n^1.3)经验值O(n²)O(1)不稳定归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定快速排序O(nlogn)O(nlogn)O(n²)O(logn)栈不稳定堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定这些结论怎么来的说两个例子。冒泡排序最坏情况是逆序输入每趟冒泡都要比较相邻元素并交换总共要跑n-1趟每趟比较n-i次累加起来就是n(n-1)/2所以是O(n²)但如果输入已经有序加个标志位优化后一趟就能结束于是最好O(n)。这个推导完全可以用上面说的嵌套循环套路做。归并排序为什么必然O(nlogn)因为它把数组对半拆分拆分深度是logn层每层合并的总代价是O(n)乘起来就是O(nlogn)。这也是分治类算法复杂度的经典套路T(n) 2T(n/2) O(n)解出来就是O(nlogn)。快速排序为什么最坏O(n²)因为如果每次选的基准都恰好是最小/最大元素划分极度不平衡递归深度变成n每层还是O(n)的划分工作乘起来就是O(n²)。它的平均情况分析更复杂涉及概率但你可以先记住结论随机化基准选择可以极大避免最坏情况。5.4 空间复杂度别忘了递归栈时间复杂度的名气太大空间复杂度经常被忽略。它衡量的是算法运行所需的辅助存储空间随n的增长情况不含输入本身占用的空间。原地排序冒泡、堆、插入、简单选择的辅助空间是O(1)归并排序需要额外数组所以是O(n)快排最坏深度为n所以栈空间O(n)平均深度logn所以O(logn)。一个高频失分点是递归的空间复杂度递归函数每次调用都会在系统栈上开辟新帧递归深度是几空间就是几个帧的量级。比如上面那个递归求和递归深度n空间就是O(n)。即使时间上看着是O(n)空间也是O(n)——两者往往一起涨。这也是为什么尾递归优化这类话题在工程里很重要它能把栈深度压到常数级别。5.5 我在分析时的三个自检习惯复杂度的题做得多了我给自己定了三个自检习惯写代码和复习时都在用第一把复杂度结论还原成哪一句话解释了它。例如归并为什么nlogn——因为logn层乘以每层O(n)。能说出这句话才算真正理解不然背出来的结论一变形就废。第二看递归优先画调用深度看循环优先写求和式。不要凭感觉猜O(n)还是O(n²)花30秒写出循环次数的累加和结论自然出现。尤其是带条件的循环和两层以上的嵌套笔算比直觉可靠得多。第三同时问自己时间和空间两个维度。哪怕题目只问时间我也会顺手标出空间因为很多后续题目比如动态规划的空间优化全靠这个意识。空间消耗和数据结构选择经常强相关链式存储空间开销大但时间灵活顺序存储省空间但移动代价高这种权衡意识要从绪论就开始练。6. 把绪论学扎实的方法考研、期末与后续章节的衔接6.1 从期末到考研绪论的知识点覆盖面如果你在准备期末绪论的选择题主要落在数据项和数据元素的区分、逻辑结构和存储结构的匹配、抽象数据类型的特性、算法五个特性、时间复杂度的量级比较、递推方程求复杂度。这些知识点都在这篇文章覆盖的范围内复习时重点看概念辨析和复杂度计算两块。如果你在准备考研408绪论常常作为送分题出现但送分的前提是你不能只背定义。真题喜欢在同一个逻辑结构不同存储结构的差异时间复杂度和空间复杂度的联合分析递归算法的调用栈开销这几个角度出题这些恰恰是绪论里最需要动脑的部分。我见过太多同学在复杂度比较题上栽跟头原因就是把O(nlogn)快于O(n²)记成了机械结论而题目稍微换成大数据量下两种算法实际耗时对比就懵了。建议的复习顺序是先梳理概念三要素、ADT、算法特性再做复杂度专项训练包括递推方程、常见排序结论、递归栈空间最后做几套综合选择题检验。绪论不需要题海但需要每种题型至少吃透一道。6.2 常见误区这些坑我见过无数人踩第一个误区是混淆逻辑结构和存储结构。典型表现是写线性表是用数组实现的还是用链表实现的这类答案时把两者混为一谈。要记住线性表是逻辑结构数组和链表是实现方式同一个逻辑结构可以有多种存储实现。这个错误在简答题里的杀伤力极大。第二个误区是只看循环不看操作。有人看到外层循环n次就直接写O(n)完全没有注意内层循环的存在或循环体里的递归调用。复杂度分析的颗粒度很重要最稳妥的方法是写出求和式而不是扫一眼。第三个误区是认为O(1)就一定比O(n)快。严格说O(1)描述的是一种增长趋势当n足够大时它必然优于线性但在n很小的时候常数因子大的O(1)操作完全可能比O(n)的实际耗时更长。工程里面经常为了常数优化做各种诡异操作算法分析里虽然忽略常数但真正落地时还是要测。学绪论的人容易把大O当圣旨这是需要纠正的。第四个误区是忽略递归的空间复杂度。如果题目问求斐波那契朴素递归的空间复杂度很多人会答O(1)理由是只是几个变量在递归。错了——系统栈里同时保留了从fib(n)到fib(1)的每一帧深度约n空间O(n)。这提醒我们看空间复杂度要追踪调用栈的生命周期不只是变量声明。6.3 我的学习路径心得绪论怎么看、何时回看这门课有个反直觉的特点绪论内容会在后面被反复实际使用。我的建议是不要指望一次把绪论完全吃透而是第一遍建立框架学到具体章节后再回头补认知。具体做法分三步。第一步快速通读绪论画出三要素、ADT、算法分析的思维导图目标不是记住所有细节而是知道后面有哪些主题需要学。第二步在学到顺序表和链表时回到绪论看存储结构的对比在学到排序时回到绪论看复杂度分析的方法在学到递归和二叉树时回到绪论看递归复杂度和栈空间的关联。第三步做完全书框架梳理后把绪论的思维导图重新画一遍这时候你对逻辑结构-存储结构-运算三位一体框架的理解会和第一遍完全不同。我还有个额外的体验想分享学数据结构最忌讳做题驱动而丢了结构感。如果把精力全花在背代码和刷题上你可能会在考试里拿到不错的分数但在面对一个真实需求时依然不知道用什么结构。相反如果你每学一个章节都先问它属于哪类逻辑结构、可能用哪些存储实现、各有什么代价做项目时就会有非常自然的选型直觉。6.4 往后章节的预告绪论在后续哪里发力最后简单说说绪论的知识在后续哪些地方会反复出现给你一个学习的地图感。线性表章节是对逻辑结构两种存储实现最好的练兵场。顺序表和单链表的增删查改就是绪论里运算三要素的完整展开栈和队列是受限的线性表理解它们的关键是只允许在特定位置操作这仍然在说运算边界问题。树和图章节考验的是逻辑结构从线性到非线性、从一对一到一对多的跃迁你会看到同一个存储结构思想在树和图中的变体。查找和排序章节则是算法分析的集中爆发各种排序的推导、各种查找算法的复杂度比较全都在用绪论里的大O工具。这也解释了为什么很多人说数据结构学到最后发现最难的是绪论。难度不在概念背不下来而在于它是全书的浓缩每一个后续知识点都是绪论中某句话的展开。先把框架搭稳后面的路就会好走很多。回到标题本身——数据结构绪论和算法分析它看似是开胃菜实际上定下了整个学期的思维基调。建议你花一周左右把这篇涉及的概念、复杂度推导、排序结论表彻底吃透再往后推进会顺畅很多。我个人在实际学习中的体会是能清楚说出为什么这个操作在这个结构上是这个复杂度的人数据结构基本不会学差而只会念结论的人往往在后面某个坎上卡住然后回头重新翻绪论。希望这篇能帮你少走这段弯路。
返回列表