前言
参考用书:王道考研《2024年 数据结构考研复习指导》
配套视频:1.0_开篇_数据结构在学什么_哔哩哔哩_bilibili
安全小白跨考准备中~通过博文绘制思维导图,复习章节的重点内容,考研一起加油~
ψ(._. )>!
第1版:查资料、画思维导图、整理错题,第1版发布~
第2版:修改第1版错误内容,调整措辞,增加思维导图~
第3版:修改第2版错误内容,删减歧义内容~
408课程之间的关系
408四门课程:数据结构、计算机组成、操作系统、计算机网络相互之间的关系。其中,计算机组成、操作系统、数据结构是从底层到顶层研究单台计算机运作原理的课程,而计算机网络是研究计算机相互之间通信的课程~
- 计算机组成:研究计算机系统的硬件组件如何相互连接和协同工作;
- 操作系统:管理计算机系统资源的软件程序,负责调度进程、管理内存和提供输入/输出服务等任务;
- 数据结构:研究如何以高效存储、检索和操作的方式组织数据;
- 计算机网络:连接在一起以共享资源的两台或多台计算机组成的系统,用途包括电子邮件、文件共享和互联网访问等。
↑截图来源:王道考研书配套教学视频
扩展:单台计算机系统详细划分可以参考下图~
数据结构的基本概念
在实际应用中,计算机面临的问题又可以分为纯数值与非数值问题。
- 纯数值问题:连续数学问题,如解方程,求积分;
- 非纯数值问题:离散数学问题,如图、数、组;
其中以非纯数值问题居多,非纯数值问题主要由两部分组成:(1)每个个体的信息、(2)个体之间的关系。通俗地说,而数据结构是研究个体之间关系的一门课程,具体定义如下——
数据结构是相互之间存在一种或多种特定关系的数据元素组合。在任何问题中,数据元素都不是孤立存在的,他们之间存在某种关系,这种数据元素相互之间的关系成为结构。
数据结构包括三方面的内容:(1)逻辑结构、(2)存储结构、(3)数据的运算。
逻辑结构,是指数据元素之间的逻辑关系,即从逻辑关系上描述数据。可以分为两大类:线性结构(线性表、栈、队列、串、数组)与非线性结构(集合、树形结构、图状结构)。如果用图像表示线性与非线性关系,可以参考下图——
存储结构,是指数据结构在计算机中的表示(又称映像),也称物理结构。它包括数据元素的表示和关系的表示。数据的存储结构是用计算机语言实现的逻辑结构,它依赖于计算机语言。
因此,存储结构是不能独立于逻辑结构存在的。
数据的存储结构主要有顺序存储、链式存储、索引存储和散列存储。
- 顺序存储:把逻辑上相邻的元素存储到物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。
- 链式存储:不要求逻辑上相邻的元素在物理位置上也相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。
- 索引存储:在存储信息的同时,还建立附加的索引表。
- 散列存储:根据元素的关键字直接计算出该元素的存储地址,又称哈希存储。
逻辑结构、存储结构的相互关系:
- 注1:数据的逻辑结构独立于其存储结构,但存储结构不能独立于逻辑结构; 数据的存储结构是用计算机语言实现的逻辑结构。
- 注2:即使两个数据结构的逻辑结构与物理结构都相同,如果数据运算不同,数据结构也可以不相同。例如二叉树与二叉排序树。
数据结构内容小结:
算法和算法评价
算法(Algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。
一个算法具有以下5个特性:(1)有穷性、(2)确定性、(3)可行性、(4)输入、(5)输出~
- 有穷性:一个算法必须总在执行有穷步之后结束,且每一步都可在有穷时间内完成。
- 确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得出相同的输出。
- 可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
- 输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
- 输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。
一个“好”的算法还具有以下4个特性:(1)正确性、(2)可读性、(3)健壮性、(4)高效率与低储存量要求~
- 正确性:算法应能够正确地解决求解问题。
- 可读性:算法应具有良好的可读性,以帮助人们理解。
- 健壮性:输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。
- 高效率:算法需要执行的时间少。
- 低存储:算法执行过程中需要的最大存储空间低。
上述特性中,确定性可能会有坑,需要单独说明一下~
- 具有随机数参与计算的指令,严格而刻板地讲不是算法:因为同一段代码在相同的输入下,输出的结果不一定是一致的~
- 在排序问题中,会出现两种合法结果的指令可能不是算法~
举栗:如下图,张三18岁、李四18岁,罗老师19岁,若以年龄排序会出现2个合法结果,这违反了确定性,也不是算法~遇到这种情况,可以增加代码判定元素位置(例如增加以姓氏拼音的首字母排序,则"李四→张三→罗老师"为排序结果),直到有唯一合法的结果作为输出为止~
算法的时间复杂度:衡量算法执行时间随输入规模增长而变化的度量。它用于估计算法的时间效率,表示算法执行所需的时间与问题规模之间的关系。
算法的空间复杂度:衡量算法执行所需的额外空间随输入规模增长而变化的度量。它用于估计算法的空间效率,表示算法所需的额外空间与问题规模之间的关系。
- 注1:上述定义中,语句通常是指最深层循环内的语句,顺序执行的代码只会影响常数项,可以忽略;
- 注2:还是强调一下,列关系式是关于 循环内的语句执行次数 与 执行时间 的关系,不是计算结果 与 执行时间的关系,我老是因为这个掉到坑里...
- 注3:算法的定义受到数学“极限”思想的影响,两个算法的时间复杂度相同,不意味着它们的执行时间相同,可能存在差异。
算法的涉及到的数据量通常较大,因此在计算中不可避免地涉及到许多数列极限求和的公式:
- 加法规则:T(n) = T1(n) + T2(n) = O(f(n)) + O(g(n)) = O(max(f(n), g(n)))
- 乘法规则:T(n) = T1(n)×T2(n) = O(f(n))×O(g(n)) = O(f(n)×g(n))
- 渐进时间复杂度(即执行次数接近无穷大时的相互比较,公式:常对幂指阶):O(1) < O(log2n) < O(n) < O(nlog2n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
算法内容小结:
扩展:此处顺便以线性表为例,比较顺序、链式、索引、散列存储方式的优点与缺点~
查找元素时间 | 插入删除时间 | 内存占用 | 适用场景 | |
---|---|---|---|---|
顺序存储 | 顺序表无序,通过遍历查找:O(n); 顺序表有序,通过折半查找:O(log n); 按位查找,通过偏移量查找:O(1)。 |
顺序表的数据元素需要满足物理相邻,插入和删除元素很可能需要移动其他元素:O(n)。 | 连续存储,占用的内存空间较少。 很难扩充表格:动态存储分配扩张需要连续空间,移动大量元素;静态存储不能扩张。 |
适用于静态数据或需要频繁访问和遍历的数据集。 |
链式存储 | 无论按值查找、按位查找,链表均需要遍历存储表:O(n)。 双链表、循环链表可牺牲空间提高效率,但时间复杂度理论上依然是O(n)。 |
如果已查到相应元素,只需要修改指针,不需要移动其他元素情况:O(1)。 但日常情况下是遍历表格查找元素+插删的连续操作,因此需要时间:O(n)。 |
每个节点包含指针,占用的内存空间较大。 链式存储的结点空间只在需要时申请分配,只要内存有空间就可以分配,操作灵活、高效。 |
适用于动态数据或需要频繁插入和删除的数据集。 |
索引存储 | 按值查找,通过折半查找:O(log n); 按位查找,通过索引表中的位置来直接访问对应的数据元素:O(1)。 |
需要维护和更新索引表:O(log n)。 | 除了主文件外还需要维护索引表,占用的内存空间较大。 | 适用于大型数据集合,需要快速查找和访问特定数据的场景。 |
散列存储 | 与散列存储选择的函数有关系,以下为拉链法的数据~ 平均情况下的时间复杂度:O(1 + α) 最坏情况下的时间复杂度:O(n) |
与散列存储选择的函数有关系,以下为拉链法的数据~ 平均情况下的时间复杂度:O(1 + α) 最坏情况下的时间复杂度:O(n) |
除了存储数据外,还需要一定的散列空间,占用的内存空间通常低于索引存储。 | 适用于大型数据集合,需要快速查找和访问特定数据的场景。 |
- 注1:索引存储与散列存储的区别并不大,区别在于索引表的映射方式;
- 注2:简单的树、图好像可以映射为线性表或者矩阵存储~
错题整理
算法的时间复杂度需要手推,根据题目条件列出f(t)=n的公式,进而计算时间复杂度~
而我由于不太明白双重循环的执行顺序、且有时脑子掉线搞错关系式的自变量和函数,经常掉到坑里;除此以外,忍不住通过土土的枚举法解题花费时间也很长...囧...
标准答案通常是以求和公式解题的,错题整理如下~
01 程序段如下:
for(i=n;i>1;i--)
for(j=1;j<i;j++)
if(A[j]>A[j+1])
A[j]与A[j+1]对换;
其中n为正整数,则最后一行语句的频度在最坏情况下是:
这个看起来是排序,从列的第一个数字开始,前后相邻两个数字相互对比,如果前面比后面的数字大则调换顺序;循环完成后,再从头开始,由第二个数字向后发起前后对比,循环到队列末尾。
那么例如列有n个字,那么第1个数字需要对比n-1次,第2个数字需要对比n-2次,以此类推,直到第n-1个数字需要对比1次。
sum=(n-1)+(n-2)+...+1=(n-1+1)(n-1)/2=O(n2)
02 以下算法中加下划线的语句执行次数为:
int m=0,i,j;
for(i=1;i<=n;i++)
for(j=1;j<2*i;j++)
m++;
从内向外分析,一共需要i、j各1次循环;i循环,从1~n,共n次;j循环,从1~2i,共2i次~
03 下列函数的时间复杂度是(17年真题):
int func(int n){
int i=0,sum=0;
while(sum<n) sum += ++i;
return i;
}
这是高斯数列求和:
得i<根号(2n),时间复杂度是O(n^(1/2))~
04 下列函数的时间复杂度是(22年真题):
int sum=0;
for(i=1;i<=n;i*=2)
for(j=0;j<i;j++)
sum++;
从内向外分析,一共需要i、j各1次循环;每当j循环1次时,sum++循环1次,所以最内层时1;每当i循环1次时,j从1循环到i,一共循环i次;i本身的循环次数遵循q=2的等比数列...因为2^i≤n,所以项数≤log2n...这个显然不是很好算,也不一定是整数。
所以,循环次数执行的次数设为t,2^t≤n,sum=1+2+4+8+...+2^(t-1),根据等比公式~
把2^t≤n代入公式,Sn的极限值为O(n)~
博文写得模糊或者有误之处,欢迎留言讨论与批评~
话说凌晨1:45爬起来改文,并不是因为我对安全专业走火入魔,也不是因为贫穷的存款使我寒窗苦读~
只是单纯地因为今天...呃,准确地说是昨天下午5点钟,不小心喝了一杯宣讲公司送的白娘子咖啡而已...顶着黑眼袋的我精神矍铄,特别想睡觉,但是一点也不困,可真是太忧伤了~::>_<::