数据结构第1章:逻辑结构、存储结构与复杂度全解析
2026/9/8 20:46:19 网站建设 项目流程

很多人翻开《数据结构》第1章,第一反应大概率是:这页怎么全是概念?逻辑结构、存储结构、抽象数据类型、时间复杂度……每个字都认识,连在一起就不知道在说什么。尤其是准备期末考试、考研408或者软考的朋友,往往直接跳过这一章去背后面的链表和排序算法,结果回头做综合题的时候,连“顺序存储和链式存储的区别”这种基础题都会卡壳。

我最早学数据结构也干过这种事,后来被一道“设计一个算法,将数组循环左移k位”的题狠狠教育了一顿,才明白第1章不是摆设,它是整门课的底层规则。这篇东西不打算复述教材,而是按我踩过坑之后的理解,把这章真正要学的东西、怎么学、怎么考、怎么用到实验报告和代码里,一次性讲透。适合三类人看:刚开课想打基础的在校生、期末或考研前突击复习的人、工作后想回头补内功的开发者。

1. 学数据结构的第1章,到底在解决什么问题

1.1 这一章不是“概念背诵章”,是“规则制定章”

很多教材把第1章写成“数据结构基本概念”,其实核心就三件事:数据怎么组织、数据支持哪些操作、操作的效率怎么评估。这三件事对应到后面每一章:线性表是怎么组织数据的,栈和队列是加了限制的数据组织方式,树和图是更复杂的组织方式,排序和查找是操作,复杂度分析则是贯穿始终的衡量标准。

所以第1章实际上是整门课的“宪法”,它规定了后面所有章节讨论问题时的统一语言。比如说,后面说“顺序表支持随机访问”,如果你不理解“顺序存储结构”意味着数据在内存里是一段连续的单元,你就没法真正明白为什么它是O(1)而不是O(n)。这个概念在第1章就出现了,但很多人没意识到它有多重要,等学到后面才回头补,效率就低了。

我个人的建议是,学第1章的时候,不要急着去背定义,而是反复问自己一个问题:如果我要在程序里存一组数据,我有哪几种存法?不同存法对增删改查有什么影响?把这个问题想清楚了,第1章的很多概念就自然串起来了。

1.2 数结构在整门课里的位置:它是地基中的地基

数据结构这门课的知识体系,大致可以分三层。最底层就是第1章的基本概念和复杂度分析;中间层是各种具体的数据结构,从线性表、栈、队列到树、图,再到散列表;最上层是建立在数据结构之上的算法,比如排序、查找、遍历。

如果你把第1章当“过场”,后面就会遇到一种很奇怪的情况:看代码能看懂,讲思路也能讲出来,但一旦题目换个问法,就不知道考什么。原因就是你没有掌握“底层规则”。比如同样是“删除元素”,在顺序存储里要移动大量元素,在链式存储里只需要改几个指针,为什么?因为两种存储结构对“逻辑相邻”的实现方式不一样。这个区别在第1章就已经奠定了。

从考试角度看,考研408、学校期末、软考,几乎所有题目最终都在考“结构选型”和“复杂度分析”这两件事。结构选型就是给你一个场景,你选什么逻辑结构和存储结构;复杂度分析就是给你一段代码,你算它的时间开销。这两项能力,全部是从第1章长出来的。地基不牢,后面盖多少层都虚。

2. 四个必须吃透的核心概念:逻辑结构、存储结构、ADT、复杂度

2.1 逻辑结构:数据之间是什么关系

逻辑结构描述的是数据元素之间的抽象关系,不关心它们在电脑里怎么存。教材上通常分四类:集合、线性结构、树形结构、图状结构。

  • 集合:元素之间“同属于一个集合”,除此之外没有其他关系,就像一袋子互不相同的珠子。
  • 线性结构:元素之间是一对一的关系,有且仅有一个起点和一个终点,每个元素最多有一个直接前驱和一个直接后继。典型的例子就是排队,每个人前面最多一个人,后面最多一个人。
  • 树形结构:一对多的关系,一个父节点可以有多个子节点,比如公司的组织架构、家族谱系。
  • 图状结构:多对多的关系,任意两个节点之间都可能有关联,比如地铁线路图、社交网络。

理解逻辑结构的关键,是把它和“物理上怎么存”分开。同一个逻辑结构,可以用不同的物理存储方式来实现。比如一个线性表,逻辑上就是一条线性的序列,但物理上可以用数组连续存储,也可以用链表散落地存储。这是第1章最核心的思维切换,也是初学者最容易混的地方。

2.2 存储结构:数据在内存里到底怎么放

存储结构(也叫物理结构)是逻辑结构在计算机中的实现方式。经典的四种:顺序存储、链式存储、索引存储、散列存储。

顺序存储好理解,就是把数据元素放到一片连续的存储单元里,像电影院连排的座位,一个挨一个。优点是可以通过下标直接算地址,随机访问很快;缺点是插入和删除往往要移动元素,而且需要预先分配空间,扩容麻烦。

链式存储是用指针把分散在内存各处的节点串起来,每个节点除了存数据,还存下一个节点的地址。优点很明显,插入删除只要改指针,不需要搬动元素;缺点是不能随机访问,想找第k个节点必须从头一个个走,而且每个节点要额外存指针,内存开销更大。

索引存储是在数据之外建一张索引表,每个索引项指向一个数据元素,相当于书的目录。查目录能快速定位页码,但目录本身也要占空间。散列存储是根据关键字直接计算出存储地址,实现“一次定位”,也就是哈希表,这个后面专门有一章,第1章只需要知道它是存储结构的一种。

我当年区分顺序和链式,靠的是这个类比:顺序存储像一群人在一间教室里按学号坐,老师喊“学号35号”,直接看过去;链式存储像一队人玩“传话”,每个人只知道下一个人是谁,想找队尾必须从头一个一个问过去。这个类比帮我在考试里避开了很多迷惑选项。

2.3 抽象数据类型 ADT:把“有什么”和“能干什么”打包

ADT(Abstract Data Type)这个概念,初看很抽象,其实特别接地气。它把数据对象、数据关系、基本操作这三样东西打包成一个整体,对外只暴露“能干什么”,不暴露“怎么实现”。

打个比方,你家里的微波炉就是一个ADT。外部面板上有“加热”“解冻”“烧烤”这些按键,这是基本操作;你不需要知道里面的磁控管怎么工作、电路怎么走线,这就是信息隐藏。你用微波炉热饭,不需要懂电磁学;你用栈的push/pop,也不需要每次关心底层是数组还是链表——只要接口一致,换实现不影响你用。

在写代码的时候,ADT思维的价值尤其大。比如你定义一个“学生管理系统”,如果一开始就把增删改查的接口定义清楚,后面把顺序存储换成链式存储,只需要改实现,调用方代码不用动。这就是为什么要学第1章:它不是让你背“抽象数据类型”五个字,而是让你建立“接口和实现分离”的工程意识,这在后面的实验和实际项目里会反复用到。

2.4 算法复杂度:衡量代码好坏的尺子

复杂度包括时间复杂度和空间复杂度。时间复杂度不是精确到“运行了多少秒”,而是看算法执行时间随数据规模 n 的增长趋势。空间复杂度同理,是看额外内存随 n 的增长趋势。

判断时间复杂度有一个很实用的小技巧:找循环。单层循环一般是O(n),双层嵌套循环一般是O(n²),三分治类的递归一般是O(n log n)。但要注意,不是所有循环都乘起来,要看循环变量和问题规模n的关系。比如下面这个求和代码:

int sum = 0; for (int i = 0; i < n; i++) { sum += i; }

这个循环执行n次,时间复杂度O(n)。但如果改成用等差数列求和公式:

int sum = n * (n - 1) / 2;

时间复杂度直接变成O(1)。第1章的复杂度题,核心就是让你掌握这种“从循环次数推导增长率”的能力,后面排序算法、树和图的操作,全部建立在它之上。

3. 把第1章变成能跑的代码:实验报告与上机实操

3.1 第一个实验该写什么:别一上来就写二叉树

很多学校的实验课一上来就是“实现顺序表”“实现单链表”,听着挺简单,但对完全不懂C语言指针的人来说,写出来的代码全是bug。我的建议是,第1章阶段先做三个小实验,难度递进,正好覆盖本章概念:

  1. 用数组实现一个整数集合的并集运算(练逻辑结构里的集合概念)。
  2. 用结构体和指针实现单链表的创建与遍历(练链式存储)。
  3. 用数组模拟一个循环队列,实现入队出队(练线性结构和对“队头队尾指针”的理解)。

这三个实验不需要多大代码量,但能逼你把第1章的概念落到语法上。特别是第二个,涉及结构体、指针、动态内存分配,这些是后面一切数据结构的操作基础。

我自己带过几次课程设计,发现一个规律:凡是链表部分靠抄的同学,后面学到树时一定崩溃。因为树的节点定义、遍历逻辑和链表是同构的,只是多了一两个指针域。第1章把链表写熟了,后面是复利式收益。

3.2 单链表实验的C语言骨架,照着敲就能跑

下面给一个最基础的单链表创建和遍历的代码骨架,注释写得比较细:

#include <stdio.h> #include <stdlib.h> typedef struct Node { int data; // 数据域 struct Node *next; // 指针域,指向下一个节点 } Node; // 尾插法创建链表,n 是节点个数 Node *createList(int n) { Node *head = NULL; // 头指针 Node *tail = NULL; // 尾指针,方便尾插 for (int i = 1; i <= n; i++) { Node *p = (Node*)malloc(sizeof(Node)); if (p == NULL) { printf("内存分配失败\n"); return head; } p->data = i * 10; // 给节点赋值 p->next = NULL; if (head == NULL) { head = p; // 第一个节点既是头也是尾 } else { tail->next = p; // 原尾节点指向新节点 } tail = p; // 更新尾指针 } return head; } // 遍历链表 void printList(Node *head) { Node *p = head; while (p != NULL) { printf("%d ", p->data); p = p->next; // 移到下一个节点 } printf("\n"); }

这段代码的要点就三个:malloc申请节点、tail->next串接新节点、p = p->next移动遍历。如果你能自己独立把这几个动作写出来,第1章关于链式存储的学习就过关了大半。顺便说一句,malloc之后一定要判断返回是否为空,这是很多同学实验报告里被扣分的地方,也是实际编程中防止程序崩溃的底线习惯。

3.3 实验报告该怎么写,才不会被老师一眼看出是抄的

写实验报告是门手艺活。我发现很多同学的实验报告,开头全是教材原文,代码部分是网上复制的一大坨,结果分析和测试数据只写一句话。这种报告其实很吃亏,因为老师看几千份实验报告,真正判断你是不是理解了,全靠“问题分析”和“结果分析”这两块。

以链表实验为例,一份及格的实验报告至少要包括这么几块:

  • 问题描述:实验要求做什么,不要抄题干,用自己的话说。
  • 设计思路:数据结构为什么用单链表,不用顺序表?这是最体现理解力的地方。你可以写“预计插入删除操作较多,链式存储不需要移动元素”。
  • 核心代码:不必须全贴,但要贴关键函数,并在旁边加注释,说明每个参数和步骤的作用。
  • 测试结果:给出一组输入和对应输出,最好包含边界情况,比如空链表遍历、删除第一个节点。
  • 复杂度分析:创建链表O(n)、遍历O(n)、在第i个位置插入O(n)(因为要先找到前驱),每个结论都要写出理由。

我特别想强调复杂度分析这一栏。它看起来像个形式,但它是把第1章概念和代码连接起来的桥梁。你写了复杂度分析,才算真正用上了第1章的知识。不写,你就是在做“打字练习”,而不是数据结构实验。

4. 期末、考研、软考、408视角下的第1章考点

4.1 这三个场景的考法差异很大,别用同一种方式复习

数据结构的考试场景五花八门,学校期末、考研408、软考中级/高级,虽然都考数据结构,但出题风格完全不同。

学校期末的特点是概念题多,判断题、选择题、填空题占了半张卷子,比如“线性结构只能采用顺序存储,这句话对吗?”(答案是错的),这类题专治“只背结论不理解原理”的人。只要你把逻辑结构和存储结构的对应关系想明白,这些题就是送分。

考研408的风格是“计算量大+代码风格强”。第1章最常考的是复杂度分析,而且经常出往年真题里的老题,比如“求下列代码的时间复杂度:for(i=1; i<n; i*=2)”这种,答案是O(log n)。408还会考察ADT描述、逻辑结构与存储结构的匹配,偶尔在算法设计题里让你自己定义结构体,完全就是在检验你是不是真的懂底层实现。

软考的风格更偏工程应用,喜欢考“在某个场景下用哪种存储结构最优”,比如“一个频繁在表头插入删除的线性表,用哪种存储方式最好”,答案是链式存储。软考还喜欢把数据结构和数据库、操作系统结合着考,反正底层逻辑都是第1章这套东西。

不管你考哪种,第1章的复习主线都是:概念题靠理解+刷题,复杂度题靠熟能生巧,代码题靠上机练习。只想考前背几页PPT是绝对不够的。

4.2 高频易错点:这些坑我几乎每一届都见到学生踩

先说第一坑:把“逻辑结构”和“存储结构”混为一谈。题目说“树是逻辑结构,二叉树是树的一种”,有同学就会问“那二叉树到底存的连续还是链式?”这就是混淆了。逻辑结构描述关系,存储结构描述实现,同一棵二叉树,既可以用数组存(顺序存储),也可以用孩子兄弟链表存(链式存储),两者不冲突。考试里一看到“逻辑”两个字,就往关系上想;一看到“存储”两个字,就往内存布局上想。

第二坑:复杂度只算循环次数,不看数据规模变化。比如代码里循环条件是i < n但循环里i = i + 2,那么执行次数是n/2,还是O(n)。很多同学不会区分常数系数和增长率。记住O()表示法丢掉常数和低阶项,但不要丢掉n的数量级。

第三坑:malloc和free不配对。写实验的时候,创建链表用了malloc,程序结束前没free,虽然考试不扣分,但如果你以后做项目,内存泄漏会把你折磨到崩溃。我面试候选人的时候,经常问“free之后指针要不要置NULL”,能答上来的不多,这就是基础没打牢的表现。

第四坑:头节点理解不到位。很多教材在链表里加了“头节点”,它不存数据,只用来统一插入删除的逻辑。有同学理解不了为什么要有头节点,考试做题就在头指针和头节点上绕晕。你用个例子辅助理解:带头节点时,删除第一个元素和删除其他元素的代码可以写成一样的;不带头节点,删除第一个元素要单独处理。这就是引入头节点最大的好处。

4.3 一张顺序复习清单,照着执行就行

结合这些年的经验,我整理了一个第1章的复习清单,不管你是期末、考研还是软考,按这个顺序走基本不会出问题:

  1. 先花两小时通读教材第1章,重点标出四类概念:逻辑结构、存储结构、ADT、复杂度。
  2. 画一张自己的结构图:左边写逻辑结构的四类,右边写存储结构的四种,中间用箭头连线,标注“可以组合”。这张图能成为你的“概念地图”。
  3. 刷20道小题,判断题和选择题都行,专门检验你对概念边界的理解,比如“链式存储只能用于线性结构吗?”(错,树和图也可以用链式存储)。
  4. 动手跑代码:实现一个有头节点的单链表,至少完成创建、遍历、在第k个位置插入、删除第k个节点四个操作。每个操作都做一次复杂度分析。
  5. 整理易错点本子,把错的题和原因都写下来,考前只看这个本子就行。

这套流程看着简单,但每一步都在练第1章的真实能力:概念辨析、复杂度推导、代码操作。比我当年闷头背书强太多。

5. 教材和资源怎么选:严蔚敏、王道、李春葆、赵海英怎么用

5.1 主流参考书各有脾气,别迷信任何一本

C语言版的严蔚敏《数据结构》是经典中的经典,几乎所有学校的课件都参考它。但这本书对新手非常不友好,很多代码的实现思路偏学术,逻辑严谨但阅读门槛高,尤其是第二章的线性表部分,光一个“线性表的链式存储”就能劝退不少人。我的看法是,严蔚敏适合当“字典”用,遇到术语不清晰的时候去查,不适合从头啃。

王道考研系列是很多考研党的救命书,它的特点是考点密集、题型全、总结到位,尤其是选择题的解析写得很详细。但它对应的主要是考试,对工作实践帮助有限。如果目标是考研408,王道加真题就够;如果你想在实验里学到真正的工程能力,还得配合上机练习。

李春葆的《数据结构习题与解析》是题库型的,题目量大、分类清楚,适合期末和考研刷题。它的答案详细,能帮你纠正很多思路偏差。语言相对啰嗦,不适合快速过知识点。

赵海英的数据结构课程在网上的资源比较多,有人求过她的百度云资料和PDF课件。她的视频风格偏学院派,讲得系统全面,适合你自学时跟着走。但我必须提醒一点:网上流传的电子书和视频资源,很多版本老旧、画质模糊,甚至和你的教材版本对不上,使用时要留意核对知识点顺序。

5.2 电子书和视频资源怎么搭配,高效又不踩坑

资源太多反而是灾难。我的实际体验是,认准“一本教材 + 一套网课 + 一个题库”的配置,不要贪多。

  • 教材选严蔚敏或学校指定版本,用来查概念和看代码。
  • 网课选一个你能听下去的老师,B站上搜数据结构,选播放量高、评论区口碑好的。赵海英、王道咸鱼老师的都行,关键是连续跟完一遍,别换。
  • 题库选王道或李春葆,按章节刷题,错题标记到本子上。

网上常见的“数据结构c语言版严蔚敏电子书pdf”“数据结构严蔚敏第三版pdf”这类资源,我建议下载归下载,PDF只适合零散查阅,系统性学习还是买实体书。原因很简单,数据结构的代码在屏幕上看效率很低,纸质书方便在书上标注画图。尤其是第1章的复杂度推导,需要反复勾画,电子书翻页翻到崩溃。

5.3 关于“数据结构八股文”和“代码必背”,我的态度是别背不会的

现在网上流传“数据结构八股文”和“408数据结构代码必背”,里面确实总结了不少高频考点,比如链表逆置、二叉树遍历的非递归写法、快排的partition模板。这些总结有一定价值,能用它快速回忆知识点,但我不建议你拿着它死记硬背。

原因是数据结构考的是“理解之下的复现”,不是“记忆之下的默写”。你背下来一个链表逆置代码,考试题目稍微改成“将链表每k个节点逆置一次”,你就抓瞎了。真正靠谱的做法是,把高频代码的每一行吃透,知道为什么要设三个指针、为什么要先保存next再改指针。吃透一个模板,比死背十个模板管用得多。

所以我建议把“八股文”和“代码必背”当作最后的复习提纲,考前一周用来查漏,而不是当作唯一学习材料。

6. 我踩过的一些坑,和几条保命经验

6.1 “听懂了但不会做题”的真相

很多同学听第1章的课,觉得老师讲的都懂,逻辑结构、存储结构、ADT,不抽象啊。但一做题就懵,什么排序算法比较次数、什么“在顺序表中插入元素的平均移动次数”,完全不知道从哪下手。

这个问题的根源是:听懂了课堂上的例子,但没把概念迁移到新场景。听懂了“排队是线性结构”,不等于你会分析“字符串也是线性结构”;听懂了“顺序表插入要移动元素”,不等于你会推导“平均移动n/2次”。迁移能力只能靠做题练,没有捷径。

我做题的方法比较土:每道题不管对错,都强迫自己写出“这道题考察了第1章哪个概念”。写不出来,说明这道题我没真正理解。这个方法帮我从“听懂了”变成“会做了”。

6.2 学习节奏安排好,第1章别拖也别赶

第1章内容不多,但概念密度高。我见过两种极端:一种是一周连翻30页,看完全忘;一种是卡在“大O表示法”上整整半个月,进度停滞。

比较合理的时间安排是三天到一周。第一天过概念,把逻辑结构、存储结构、ADT理解清楚;第二天专门搞复杂度,把例题手算一遍,再自己出几道题验证;第三天到第五天上机写代码,把链表实验做完;剩下的时间刷题和整理错题。战线太长容易疲劳,太短则消化不良。

我自己最喜欢的时间节奏是“每天专注2小时,连续5天”,比周末疯狂学一整天效果好得多,因为每天接触的时间短,大脑有时间做“后台固化”,第二天再看昨天的内容会觉得很简单。

6.3 最后分享一个压箱底的小技巧:把每章压缩到一张A4纸

从第1章开始,我会在学完一个大的知识块后,把核心知识点压缩到一张A4纸上。不用写很长,就写关键术语、关键公式、典型例、易错点。

比如第1章的A4纸上,我会写:

  • 逻辑结构:集合、线性、树、图(一对一、一对多、多对多)
  • 存储结构:顺序、链式、索引、散列(连续vs分散、随机vs顺序)
  • ADT:数据对象 + 关系 + 操作,接口与实现分离
  • 复杂度:找循环、算次数、去掉常数和低阶项
  • 易错:顺序存储不一定是数组,链式存储不是只能存线性结构

这张纸在身边的好处是,每天花一分钟扫一眼,知识点不容易忘。到了期末或者考前,这本“A4纸集”就是你最有力的复习资料。我靠这个方法,期末复习时间压缩了至少三分之一,而且心里特别有底。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询