计算机数据结构-第一章

数据结构基本概念

数据

数据元素、数据项

之间的集合关系

这里需要注意的是元素的数据前驱和后驱

一对多

就相当于每个人都是个体,产生联系后就连线,多对多

小结

存储结构

顺序结构

一个挨到一个的表示逻辑上的相邻关系

链式存储

不要求位置相临,但是可以有指针来索引

索引存储

散列存储

采取这些时候的优点

运算

算法

小结

算法的时间复杂度

'时间复杂度就是用于评价一个算法的', '时间开销这样的一个指标', '那首先我们用自己的直觉来想一想', '可以用什么样的思路来评判', '一个算法的时间开销呢', '其实站在我们程序员的角度来看', '一个算法', '它肯定终归是要用某一种程序代码', '来实现的', '那我们要评判这个算法的时间开销', '是不是很自然的', '可以想到', '我们只需要让这段程序', '这段代码让机器跑一下', '然后看一下它的运行时间是多少', '是不是就可以统计出一个算法的时间开销', '也就是采用事后统计的方式',

存在问题吗

'其实存在一些问题', '第一我们的这段程序代码', '它的执行速度是不是和机器性能是有关的', '在好的机器上可能很快就能运行', '在差的机器上', '可能要很久才能运行', '所以你不能说一个算法统计出来', '它运行时间短', '它就一定优秀或者运行时间长', '它就一定不优秀', '这是不客观的', '另外算法的时间开销', '还和呃', '你实现这个算法所采用的编程语言', '是有关系的', '越高级的语言执行效率越低', '比如你用c语言写的程序', '一般就要比java写的程序啊', '效率上要更高一些', '因为java是更高级的语言', '所以同一个算法用不同的语言实现', '也会导致我们最终统计出来的', '看到的这个运行时间会有偏差', '但本质上算法还是同一个算法', '我们并不能说这是算法设计上的问题', '只不过是由于使用的编程语言不一样', '导致的', '再一个方面', '算法的时间开销', '还和这个编译程序产生的机器指令', '质量是有关的啊', '那这个不再展开', '看不懂也没关系', '最后我们还想强调', '有的算法它是不能事后在统计的', '比如如果你写的算法', '是用于控制导弹轨迹的', '等他打到错误的地方', '我再来统计运行时间', '那这样就没有意义了', '因此如果用事后统计', '这样的方式', '来评估一个算法的时间开销的话',

算法', '它的运行时间t', '应该是和他要处理的这个问题', '规模大小是有关的对吧', '如果问题规模越大', '那这个算法它的运行时间也理应更长', '所以算法的时间开销t', '应该是和问题规模n之间','呈现某一种函数关系的', '所以当我们在分析一个算法的时间', '复杂度的时候', '最重要的就是要尝试着用问题规模', 'n这个参数来表示出算法的时间开销好', '

'这个父亲也就是钢铁侠告诉他女儿说', '我爱你1000遍', '然后这女儿说', '那我爱你3000遍好', '那我们设计一个简单的算法', '用来实现表白爱你n遍', '这个事情用c语言来实现的话', '就是这个样子啊', '我们把它称之为逐步递增型爱你', '这样定义一个变量i啊', '表示的是爱你的程度', '然后接下来就会进行n次循环', '每次会导致i的值加一', '并且会打印出爱你的程度', '然后最后还会打印出这样的一句话', '那我们在main函数里调用这个逐步递增型', '按你这个函数而传入的n的值', 'n的值是3000', '这儿的n其实就是问题的规模', '因为传入的参数n越大的话', '那么这个循环的次数也会越多', '

我们写了这样的五行代码', '给它分别进行编号', '我们默认执行这样任意一行代码', '所花的时间是相同的', '虽然实际上他们执行时间肯定不一样', '但是如果考虑太多因素的话', '我们就没办法来评价这个算法了', '所以我们把问题简化好', '那接下来我们来数数看', '这些代码分别执行了几次', '第一行代码很显然只执行了一次', '第二行代码', '它是一个while循环', '做了一个条件判断', '不难看出', '这个循环里边的代码总共会执行3000次', '但是这个循环的条件判断', '它需要执行3001次', ' 因为执行了第3000次之后还需要进行判断', '发现i的值已经到3001了' , '那在这个时候它才可以跳出循环', '执行第五句', '所以这个条件判断', '这一句应该是执行了3001次', '而里面三四这两句执行了3000次', '那第五句很显然也只执行了一次', '所以当问题规模为3000的时候', '这个算法的执行', '就应该花费这么多单位的时间', '那如果把3000换成n的话', '我们也可以得到呃', '时间开销t和n之间的一个表达式关系',

'分析的方法和刚才是一样的', '如果一行代码执行的时间需要1ms的话', '那么这个式子是不是说明', '当问题规模为n的时候', '这个算法的时间开销应该是3n加三',

''有什么n的三次方加上什么6n的平方', '加上一堆东西', '那当这个时间复杂度的表达式', '变得很复杂之后', '我们就很难从这个表达式当中看出', '一个算法它到底是好算法还是坏算法', '所以接下来要探讨的第一个问题是', '我们是否可以忽略', '这些表达式当中的某些部分', '或者说是否可以把这个时间复杂度的', '表达方式给简化呢'

第二个要探讨的问题是', '如果一个算法它有好几千行代码', '当这个代码很长的时候', '我们如果还用刚才这种一行一行来数的', '这种方式来统计的话', '那显然这种思路是不切实际的好', '那首先来看第一个问题', '能否简化时间复杂度的表达式', '那我们刚才的那个算法', '它的时间复杂度是这个样子', '那假设现在还有另外的两个算法', '它们的时间复杂度和问题规模n之间的关', '系分别是这个样子', '其实不难想到', '当问题规模n足够大的时候', '我们可以忽略掉这些表达式当中', '更低阶的这些部分**', '让大家直观地感受一下', '当问题规模n等于3000的时候', '对于第一个算法的时间复杂度', '我们只保留它前面更高阶的这个部分', '也就只保留3n', '那么我们计算的结果应该是得到9000', '这是它的时间开销', '而如果把表达式的后面部分', '也考虑进去的话', '那计算结果是9003', '其**

再来看第二个算法', '如果我们只保留它阶数最高的这一项', '也就是n的平方的话', '那么计算的结果n的平方是这个样子', '而第二个算法的时间开销的精确表达', '是这个样子', '其实区别不大对吧', '也就是说如果现在有这样的一个算法', '它的时间开销和问题规模', 'n之间的关系是tn等于n的平方', '那么我们可以认为', '这个算法和t2 这个算法其实差不多', '是一样优秀的对吧', '谁也不比谁好多少', '谁也不比谁差多少', '所以当我们评价t2 这个算法的时候', '其实可以把它的时间开销', '后面的这些低阶的部分给去掉 ', '就不考虑进去', '对于第三个算法其实也是一样的', '我们只保留它的时间开销', '表达式的最高阶的这一项', '那么算得的结果', 'n的三次方和它本身的这个精确表达', '其实差的不大', '同样的也就是说', '如果有一个算法', '它的时间开销和问题规模n之间的关系是', '时间开销等于n的三次方', '那么这个算法的优劣程度', '和这个算法的优劣程度也差不多', '因此我们得出的结论是', '一个算法的时间开销表达式', '我们只需要保留接触更高的部分就可以了'

加法规则

'第一个算法', '我们可以认为它的时间开销是等于3n', '第二个算法', '我们可以认为它的时间开销', '是等于n 的平方', '第三个算法', '我们可以认为它时间开销是n的三次方', '其实当我们在评价一个算法优劣的时候', '甚至还可以把这个常数项也给忽略掉', '也就是说如果有一个算法', '他的时间开销和n的关系是tn等于n', '那么当问题规模为3000的时候啊', '这个算法的时间开销', '就应该是3000个 单位的时间对吧', '你说这个算法和时间开销为9000的算法', '区别大吗', '看起来相差三倍', '但其实他们的时间开销', '也是同一个数量级的'

**第一个叫做加法规则', '**就是说多项相加的时候只保留最高阶的项', '并且系数变为一', '如果硬要套公式的话', ' '注意这儿我们已经把这个系数变为了一', '然后加法规则指的是多个大o相加的时候', '我们只保留阶数最高的数量级', '最高的那个大o', '也就是只保留最高的这一项', '所以t3 我们可以把它记为t3 ', '等于o的三次方', '这所谓的加法规则', '其实和我们刚才说的是同一个事情',

一个要注意的是乘法规则', '就是当两个大o相乘的时候', '需要把它们合并', '那来看', '一个会同时用到', '加法规则和乘法规则的例子', '假设 有这样的一个算法', '它的时间开销和问题规模n之间的关系', '是这样的', '那按照加法规则', '我们只需要把相加的这两项', '给它套上一个大o就可以了', '就是表示它的数量级', '其实这已经用到了乘法规则**', 'n方乘以log n其实是两个呃', '关于n的表达式的相乘吗', '所以如果要用大o表示法', '表示它们的数量级的时候', '我们只需要把它俩相乘合并就可以了', '也就是在外面统一套一个大o好',**

时间复杂度排序

例题

'这是大家在进行算法复杂度分析的时候啊', '经常会碰到的一些常见的数量级', '从左到右依次递增',

**'**这个要很熟练', '因为我们已经说了', '在计算复杂度的时候', '我们需要判断到底哪一个', '当我们在讨论一个算法的时间', '复杂度的时候', '我们并不需要给出这个算法的时间开销', 't和n之间的详细的表达式', '只需要关注这个表达式的数量级就可以了', '好接下来看第二个问题', '刚才我们求问题', '规模n和时间开销', 't的方法是一行一行代码来分析', '但是如果一段程序它有好几千行代码', '那很显然一行一行来数', '这种方法是不实际的', '比如我们在第一行代码之前', '又插入了1000行顺序执行的代码', '所谓顺序执行的代码', '指的是不带有循环的代码', '那如果是这样的话', '我们的这个算法的时间开销', 't又需要多加1000', '因为它会多执行1000行', '那如果代入n的话', '后面加的这个常数就应该变成是1003', '而不是三', '我们知道', '我们只需要关注这个时间开销的数量级', '就可以', '也就是用大o表示法来记', '虽然后面的这个常数项看起来大了很多', '但是如果用大o表示法来记的话', '其实这两个表达式', '它们的数量级都是on这样的数量级', '因此我们得出结论', '顺序执行的代码它只会影响常数项', '可以忽略',

'也就是说我们并不需要一行一行数', '前面的这1000行代码', '甚至不需要数第一行和第五行代码', '我们只需要关注循环这个部分就可以了', '那之前我们在分析这个循环', '内部的语句的时候', '其实我们把整个循环所涉及到的', '这三条语句都已经考虑进去了', '但是经过之前的分析', '我们知道', '这样的系数最终肯定都是变为一的', '当我们只考虑这个表达式的阶数的时候', '其实不管这个系数是多少', '最终我们肯定都会把它变为一',

嵌套循环

只需要关注这里的最深处的

'也就是说', '其实我们只需要分析这个循环当中的', '某一条语句', '某一个基本操作就可以了', '我们只需要随便挑一个语句来分析', '这个语句的执行次数和n的关系', '对于这个算法来说', '循环里边的任意一条语句啊', '像四这个语句', '它的执行次数就应该等于n', '因此我们最终得到的这个算法的时间', '复杂度就是o n这么多好', '那既然我们只需要关注代码当中', '循环的部分', '那如果说有嵌套的循环', '那这种代码应该怎么分析呢', '我们在这个while循环里面', '又加了一个for循环', '这个for循环会循环n次', '然后外面这一层while循环也会循环n次', '因此里边的这个for循环', '总共会执行n乘以n', '也就是n的平方这么多次', '因此考虑时间开销的话', '外层循环的这些语句', '他们的时间开销应该是o n这个数量级的', '因为它总共执行n次码', '而内层循环的这些语句', '它的执行次数就应该是n的平方', '这样的数量级', '那根据之前提到的加法规则', '我们只需要保留更高阶的这个部分', '也就是保留n的平方', '这就是这个算法时间复杂度的数量级', '所以我们得出的第三个结论是', '如果有多层嵌套循环的话', '那么我们只需要关注最深层的这个循环', '它到底循环了几次', '我们需要找到它循环的次数和问题规模', 'n之间的关系', '这样就可以求出算法的时间开销好',

指数循环

'那到此为止', '我们就回答了刚开始提出的两个问题', '这儿给出了第三个算法', '这个算法会设置一个变量i', '这个i的值表示的是爱你的程度', '然后这儿有一个while循环', '每次i的值会翻倍', '也就是乘以二', '直到i的值比n大的时候', '它才会跳出这个循环', '然后执行最后这一句', '这个算法的时间复杂度', '我们知道像这一句', '还有这一句', '这些顺序执行的语句', '我们可以不管', '我们只需要关注循环的部分', '并且挑选这个循环当中的随便一条语句', '然后看一下它的执行次数和n之间的关系', '那我们假设这个print f执行了x次', '也就是说这个循环总共循环了x次这么多', '那i的值刚开始是一', '第一次循环是不是会导致i的值变为二', '而第二次循环又会使i的值再次翻倍', '也就变成四', '然后再往后的话是86 32', '以此类推', '这是第一次循环', '第二次循环', '第三次循环', '所以当循环了x次之后', 'i的值应该是二的x次方这么多对吧', '那根据这个循环的条件', '我们知道当i的值大于n的时候', '这个循环就可以跳出', '也就是说当二的x次方大于n的时候', '这个循环就可以结束', '不难理解', '当循环次数x等于log 2 n加一的时候', '刚好可以让i的值大于n', '也就是说这个循环里边的某一条语句', '它的执行次数就应该是这么多', '所以这个算法的时间开销', 'tn应该和x这个表达式是同等数量级的', '那根据加法规则', 'o的log 2 n加上o1 ', '我们需要把后面这个舍弃', '只保留高阶的部分', '

因此这个算法的时间复杂度就应该是o的', 'log 2 n好', '我们需要传入一个数组', '这个数组的长度是n这么多', '然后这个数组中乱序的存放了一到n', '这些数', '我们的这个算法要做的事情是', '从这个数组的第一个元素开始', '依次往后寻找', '要找到这个数组中值为n的那个

搜索数字型

分情况','输入的这个flag数组不一样', '

所以大家会发现对于这个算法来说那么它的这个循环次数也会不一样', '因为它是从第一个元素开始', '依次往后查找的', '所以如果他要找的n这个元素', '它刚好是在flag这个数组的第一位', '那么是不是这个循环只需要循环一次', '它就可以结束了', '

如果n这个元素', '它是在flag数组的最后一位','那是不是这个循环就必须循环n次', '直到查到最后一个元素', '它才可以跳出循环

', '因此当我们计算这个算法的时间', '复杂度的时候就需要考虑不同的情况', '最好的情况就是元素n在第一个位置', '这种情况下这个循环只需要循环一次', '所以这个算法的时间复杂度应该是o1 ', '

就是常数级的', '这是最好的情况', '那这个时间复杂度', '我们把它称之为最好时间复杂度', '那

最坏的情况就是我们说的第二种情况', '元素n在最后一个位置', '在这种情况下', '这个循环需要执行n次', '所以这算法的时间复杂度变成了o o', '那如果不考虑这两种特殊的情况', '我们考虑平均情况的话', '我们应该怎么计算呢', '

如果要考虑平均情况的话', '我们会假设这个元素n', '也就是说flag这个数组', '它其实就是有n个这样一个一个小格子', '然后n这个元素有可能出现在其中的', '任意一个格子当中', '并且出现的概率都是n分之一好', '

那假设n这个元素出现在第一个位置的话', '循环的次数应该只需要循环一次对吧', '如果n出现在第二个位置', '那应该循环两次', '如果n出现在第三个位置', '那应该循环三次 ', '以此类推', '由于这个元素出现在每个位置的概率', '都是n分之一', '所以我们在乘上这个概率权重', '这样的话就可以得到一个数学期望', '平均来看', '这个算法要找到元素n所需要的循环次数', '平均是二分之n加一这么多', '那如果用大o记法的话', '它的数量级就应该是o n这么多'

总结

时间复杂

算时间复杂度', '时间复杂度是用于衡量一个算法', '它的时间开销和问题规模n之间的关系', '而这个小节中我们要学习的空间复杂度', '它是用于衡量一个算法', '它的内存空

逐步递增型

我们首先来简单的介绍一下', '在一个程序运行的时候', '需要哪些内存空间', '首先当这个程序运行之前', '需要把这个程序相关的程序代码', '把它放入到内存当中', '当然实际放到内存里面的程序代码', '其实并不是我们在这儿所看到的','

这种高级语言的代码', '肯定是经过编译之后形成的', '相应的机器指令', '那当我们编写完这样的一个程序之后', '其实这个程序它放到内存里', '需要占多大的空间', '这个是已经确定的', '也就是说', '内存当中用于存放程序代码的这篇呃', '存储空间', '这片存储空间的大小', '其实和我们的问题规模是没有关系的', '好那

我们随便假设一个值', '假设它占100个字节这么大', '接下来要执行的代码已经放入内存了', '那么cpu就可以开始执行这些', '一行一行的代码', '那注意观察我们写的这个函数', '或

者说我们写的这一小个算法', '在调用它的时候会传入一个int型的参数', '然后在这个地方', '我们还会定义一个int型的变量i', '所以当这段代码运行的时候', '

内存中还需要有这样的一小片区域', '用于存放和它相关的这一系列的啊', '局部变量参数这些信息', '那i和n都是int型的变量', '所以至少还需要八个字节', '用于存放和他相关的数据', '当然这我们讲的并不严谨', '其实除了i和n之外', '还会存一些其他的信息', '但是道理都是类似的好

', '那接下来需要注意的是', '在这个例子当中**', 'n是问题规模'**, '但是不管n的值怎么变化', '这个算法在执行的过程当中', '它所需要的这个内存空间大小', '都是固定不变的一个常数值', '按照这个地方我们的假设来看', '

不管问题规模n怎么变化', '这个算法它在执行的过程当中', '都只需要108个字节', '与变量n没有关系

这么大的内存空间', '所以这个算法的空间复杂度', '它就是常数阶的', '那这个地方的原理', '其实和时间复杂度是类似的', '这儿的s表示的是space', '就是空间的意思', '上个小节我们学的时间复杂度', '是用tn表示', 't表示的是time', '那像这个算法这样', '如果这个算法它所需要的内存空间'

和问题规模n并没有关系', '也就是说它的空间复杂度是常数阶的话', '那么我们就可以称这种算法', '它可以原地工作', '这个术语

有可能会在选择题当中进行考察', '需要稍微注意一下好', '类似的方法', '我们再分析下一个算法', '在这个算法当中', '我们定义了一个int型的数组', '这个数组的长度是n n是我们的问题规模', '

所以在这个算法当中', '它运行的过程中所需要的内存空间大小', '就会和这个问题规模n有联系', '同样的', '如果我们假设一个int型的变量', '占四个字节的话', '那么首先存放这个参数', 'n是不是就需要四个字节', '接下来这个int型的数组', '每个数组元素都会占四个字节', '然后它总共有n个元素', '所以这个数组总共会占4n这么多的空间', '然后i这个变量它又会占四个字节', '所以加起来就应该是4n加八', '这么大的空间', '所以这个算法它所需要的空间', '就和问题规模n有关系了', '那和时间复杂度类似', '当我们在谈论一个算法的空间', '复杂度的时候', '其实我们只需要关注它所需要消耗的', '这个空间是什么数量级', '什么接触就可以了', '所以我们同样是用大o表示法来表示', '那么4n加八这个表达式', '它的接触其实就等于n对吧', '因此这个算法的空间复杂度', '应该是o n这个量级', '那经过刚才的
'相信大家能够体会到', '如果说在函数当中我们定义了某些变量', '但是这个变量它所占的空间和问题规模', 'n没有关系的话', '那这个类型的变量', '最多也就会在我们的这个呃表达式当中', '给我们增加一个常数项', '但是由于我们最终都是要转换成这种大', 'o表示法', '就只关心它的接触的', '所以这种常数项对我们最终的这个结果', '不会产生任何影响', '因此以后当我们在分析一个算法的空间', '复杂度的时候', '其实我们只需要关注它所需要的存储空间', '大小和问题规模相关的这些变量就可以了',

'好再看下一个例子', '在这个例子当中', '我们定义了一个二维数组', '它的大小是n乘n', '那根据刚才分析', '我们知道像n这个参数', '还有i这个变量', '并不需要把这两个变量给考虑进去', '因为存储这两个变量', '最多也就增加一个常数项', '而唯一和问题规模n相关的变量是flag', '这个数字', '当问题规模为n的时候', '存储这个数组所需要的内存空间', '应该是四乘以n的平方', '

因为一个int型的变量是四个字节吗', '所以这个算法的空间复杂度', '它应该是n的平方', '这样的一个数量级好继续看下一个例子', '在这个例子当中', '我们定义了一个二维数组', '它的大小是n乘以n', '然后一个一维数组它的长度是n', '所以当这个算法运行的时候', '内存当中需要存啊这样的两个数组', '同时也需要存其他的一些变量', '那存储flag', '这个数组所需要的内存空间大小', '它的数量级应该是n方这么多', '存储这个一维数组', '它所需要的内存空间开销', '应该是这样的一个量级', '然后存储其他的这些变量所需要的啊', '内存空间大小应该是一个常量', '也就是o e这样的量级',

同样适用于我们的加法原则

递归型

那上个小节我们提到过', '当多个大o相加的时候', '我们只需要保留阶数最高的那个大o', '也就是n方这一项就可以了', '好那之前我们提到的这些例子当中', '导致一个算法的空间复杂度变化的', '主要原因是这个算法当中定义的某些变量', '存储这些变量需要一些内存空间的开销',

'但是还有一种情况',

'也会导致内存空间开销的变化', '就是函数调用的时候', '也会导致内存开销的增加', '我们来看这样的一个例子'
, '在这个函数当中定义了三个局部变量'

, '那根据之前的分析', '我们知道这些变量它所占的空间大小', '应该是一个常量', '然后当这个参数n大于一的时候', '它又会递归的调用自己这个函数', '让这次传入的参数减一', '然后最后会进行一个打印输出', '打印出当前这个函数参数n的值', '那我们在main函数里对love you', '这个函数进行调用啊', '传入的参数是五', '那最终运行的结果是这样的',

'那我们来分析一下这个递归调用的过程', '

刚开始这段程序要运行', '需要把它的程序代码放入内存当中', '这个和之前的一样', '然后这片空间它的大小肯定是固定的', '

和问题规模没有关系', '好接下来main函数调用了', '按你这个函数', '然后传入的参数是五', '这个n的值是五', '好接下来这个函数开始运行', '在这儿', '它会声明三个变量a b c', '那是不是和我们之前分析的那些函数一样', '我们也需要把这个函数运行过程中啊', '所涉及到的这些参数', '还有啊变量这些东西给存放到内存里', '

对吧好'

'那如果继续往后运行', '发现此次n的值是大于一的', ' 所以这个函数又会调用它自身', '但是这一次它传入的参数应该是5-1', '也就传入四好', '那在这次的调用中', 'n的值是四', '同时在这次调用当中还会再声明一次', 'abc这几个变量对吧', '所以这一次函数调用相关的这些参数', '还有变量', '同样也需要在内存当中开辟一片空间', '来存放这些数据', '在第一层调用当中', 'n的值是等于五对吧', '然后它里边有a b c这些变量', '然后在第二层调用当中', 'n的值其实是四', '虽然它们都叫n', '但是在内存当中其实是两份不一样的数据', '同时在第二层调用当中', '它也会有a b c这几个变量', '同样的', '虽然名字和上面这个看起来一样', '但其实在内存当中', '这几个变量都是存放在不同的区域的好', '那再往后的几层调用是不是都一样啊'

, '每一层的调用都需要把这一层调用当中的', '参数n还有abc这些局部变量', '都用一片专门的内存空间用于存储', '然后当调用到第五层的时候', 'n的值已经变成了一

', '这个条件已经不满足了', '所以这次的调用会直接跳过这个if语句', '然后执行print f这一句', '那此时这个n的值是一', '所以就打印出了这一行信息', '那接下来这一层函数调用结束', '返回之后', '就可以把这层函数相关的这些信息', '数据给删除了', '当返回到这一层的时候', '系统会根据内存当中保存的这些信息', '来恢复这个函数相应的执行环境', '好

'我们再来理解这个函数的递归调用', '所带来的内存开销到底是怎么一回事',

'在我们这举的这个例子当中啊','这个变量n还有a b c这几个变量', '它们所占的空间大小都是固定的对吧', '总共是16个字节','所以我们可以简单的认为', '每一层的函数调用', '它大概需要16个字节', '这么大的空间来存储相应的信息', '当然真实情况是除了nabc这些之外', '还会存一些像函数的返回地址啊', '之类的一些信息', '只只不过这儿不想讲太多复杂的细节', '那我们所需要知道的就是', '每一集的函数调用啊', '肯定都需要k个字节', 'k是一个常数这么大的空间', '那当n等于五的时候**', '他总共发生了五层的这种递归调用', '因此这个递归调用的层数', '和我们的问题规模n刚好是相等的',** '所以当问题规模为n的时候', '它所需要的内存空间大小', '就应该是kn个字节这么多', '如果用大o表示法只关注它的阶数的话', '那么我们可以把这个k给去掉', '所以这个程序它的空间复杂度', '就应该是这样的一个数量级'

同样的,我们在这里加上int n之后

这样相当于是等差数列求和了

小结

在我们的考研当中', '大部分和递归相关的这种空间复杂度的分', '析和这个题目都是类似的啊', '空间复杂度都是等于递归调用的深度', '因为每一层的递归调用啊', '所需要的这个内存空间大小都是一个常量',

'k个字节', '但其实也会有一些算法', '它每一层的递归调用', '所需要的内存空间大小是不一样的', '比如我们把刚才那个递归程序', '给稍微改一改呃', '每一层的递归都会定义一个int型的数组', '这个数组的长度和这一级递归的参数', 'n是相同的', '也就是说低层调用的时候', 'n的值为五', '那么这个数组的长度就是五这么多', '接下来由于n大于一', '所以下一集的调用这个n的值', '传入的参数的值就变成了四', '因此下一集的调用当中', '这个数组的长度也为四', '那以此类推', '总之由于这儿声明的这个数组长度', '和这一级调用所传入的参数n是有关的', '因此每一集的函数调用当中', '用于存放这些变量', '所需要的空间大小肯定也是不一样的',

'最下面这一集调用数组的长度为一', '然后第二集的调用数组的长度为二', '第三集的调用数组的长度为三', '那以此类推', '第n级的调用数组的长度就应该是n', '所以综合来看呃', '各级递归调用所需要的存储flag', '数组的空间大小就应该是这样的一个值', '那这是一个简单的等差数列求和', '算得的结果是这样的', '那显然在这个算法当中', '它的空间复杂度sn就应该是n的平方', '这是它的数量级', '当然

我们在考研当中', '并不会遇到这么复杂的情况', '绝大多数的题目都和前一个例子一样', '也就是当发生函数递归调用的时候', '空间复杂度就等于递归调用的深度好', '那么这个小节当中', '我们学习了', '如何计算一个算法的空间复杂度', '那在考研当中', '我们有可能会遇到啊', '对普通程序的分析', '也有可能会遇到递归的这种情况', '当我们在分析一个普通程序', '它的空间复杂度的时候啊', '相对来说简单一些', '我们只需要找到所占空间大小和问题规模', 'n相关的那些变量', '然后分析这些变量', '它所占的空间大小和问题规模', 'n之间的关系就可以了', '那在表示一个算法的空间复杂度的时候', '我和时间复杂度一样', '

我们只需要关心它的数量级',

'也就是会使用到大o表示法', '所以我们在实际分析的时候', '其实并不需要像之前一样考虑', '比如说一个int型的变量占四个字节', '还占几个字节这样的信息', '因为无论占四个字节还是占几个字节', '在套了一个大o之后', '最终只关心它的数量级嘛', '所以我们肯定会把它前面的', '这个系数给去掉', '因此在实际分析的时候并不需要考虑啊', '什么样类型的变量', '它到底占多少个字节', '我们只需要关心它的数量级就可以了', '好那比较难分析空间复杂度的是递归程序', '只不过我们在考研当中遇到的递归程序', '大多数情况下', '我

们只需要看这个递归调用的深度', '和问题规模n之间的关系就可以了', '一般来说在考研当中遇到的就是呃', '这个调用的深度x的数量级', '就是它的空间复杂度', '那在计算空间复杂度的时候', '其实大o表示法啊', '相关的这些运算技巧和时间复杂度', '那些都是通用的', '这就不再赘述啊', '其实考研中', '我们更多会考察的是', '对于时间复杂度的度量', '空间复杂度考察的频率相对来说要低很多', '在之后学习的很多算法当中', '我们还会带大家继续分析空间复杂度', '所以以后还会有很多时间的机会好的', '那么以上就是这个小节的全部内容']

线性表

'那我们在绪论当中提到过', '当我们在学习一个具体的数据结构的时候', '需要关注数据结构的三个方面','逻辑结构', '物理结构和数据的运算', '

那这个小节中', '我们首先介绍线性表的定义和基本操作', '其实就是要探讨这种数据结构', '它的逻辑结构是什么样的', '然后还要探讨', '我们需要对这种数据结构', '实现哪些基本的运算', '也就是所谓的基本操作', '在之后的小节中',

'我们还会探讨', '使用不同的存储结构来实现线性表', '那当采用不同的存储结构的时候', '对于数据的运算的具体实现也会不同', '这一点之后', '我

们会用具体的代码来带大家加深理解好', '那首先来看一下什么是线性表', '如果讲大白话的话', '所谓线性表就是指各个数据元素', '它们之间的逻辑关系', '逻辑结构是这种一条线的结构', '就是被串到一起', '数据元素之间有这样的前后关系', '

那么在课本中', '给了文字性的比较严谨的定义', '线性表', '

它是具有相同数据类型的', 'n个数据元素的有限序列', '如果用l来表示一个线性表的话', '那么可以用这样的方式来表示l', '这个线性表由n个数据元素组成', '分别是a一到an', '那我们在这个定义中', '需要注意这样的几个点', '首先线性表当中的各个数据元素', '它们的数据类型都是相同

的', '比如你的这个数据元素它是int型的话', '那么其他的这些数据元素**', '它们也都需要是int型** ', '当然你也可以自己定义某一种结构类型', '比如叫struct a', '那你可以把你自己定义的这个结构类型', '作为数据元素的数据类型', '所有数据元素的数据类型都相同', '这一点意味着各个数据元素', '它们所占的存储空间是一样大的', '这个特性可以帮助计算机', '快速的找到某一个具体的数据元素',

'第二个需要注意的地方是线性表', '它是一个序列', '那所谓的序就是指有次序', '各个数据元素之间有这样的先后次序', '这个很好理解', '

第三个需要注意的点', '线性表中的数据元素数量是有限的', '比如举一个反例', '如果说所有的整数按照递增的次序来排列', '那这样的数据结构**', '它既满足了各个数据元素相同这个特性', '同时也满足了各个数据元素之间有次序',** '这样的特性', '但是由于这儿提到的是所有的整数', '而整数的数量它是无限的', '因此它不能算是一个线性表好', '那大家还是要注意一些'

, '在做题的时候会遇到的术语', '首先这个线性表的长度n','我们把它称为表长', '而如果它的表长等于零的话', '那么我们就称这样的一个线性', '表示一个空表', '然后注意在这个地方'

, '我们描述线性表当中的', '各个数据元素的时候', '这个角标是从一开始的', 'a1 ', '表示这个线性表当中的第一个数据元素', 'a2 是第二个数据元素'**, 'ai是第i个数据元素', '**那所谓的第几个',

'我们用一个专业术语描述', '叫做数据元素在线性表中的位序', '然后一个线性表中的第一个元素', '我们称为表头元素','最后一个元素称为表本元素', '除了线性表当中的第一个元素之外', '其他的所有元素都可以找到一个直接前驱', '也就是排在他们前面的数据元素', '

这是前驱的概念', '而除了最后一个元素之外', '其他的每个元素都可以直接找到一个', '它的直接后继', '这是后继的概念', '那这里要再次强调未戌这个概念', '位序是从一开始的', '但是我们在程序当中定义一个数组的时候', '数组下标是从零开始的',

道大家在看到线性表这个术语的时候', '这个表字会让大家联想到什么', '对我而言', '当我看到表这个字的时候', '我第一个联想到的是类似于这样的东西', '我在刚开始学的时候会觉得说', '为什么这样的一个线性结构的关系', '要把它称为表呢', '其实可以从线性表的英文', '术语当中找到答案', '线性表的英文叫linear list', '那linear其实就是现行的直线的线状的', '它是由line这个单词变来的', '那line就是线啊', '比如大家喜欢看的天线宝宝', '就是skyline baby对吧', '那list这个单词它有列表的意思', '比如代办事项是to do list', '那像这种列表'

, '它就是由一个一个的元素组成的', '这就和我们线性表的样子对应上了', '所以我觉得它为什么要翻译为线性表呢', '可能就是因为这个list', '它本来就有列表的含义', '再换一个角度理解', '如果说这样的一个数据元素', '它里边包含了多个数据项的话', '那么从形式上看这样的一个数据结构', '它保存的内容不就是这样的一张表吗', '所以这是为什么这种数据结构它叫线性表', '而不是什么线性串之类的原因', '好的', '那认识了线性表的逻辑结构之后', '我们来看一下', '需要对线性表实现哪些基本操作', '或者说基本运算',

线性表的基本操作

'首先需要实现的两个基本操作', '

初始化一个线性表', '还有销毁一个线性表','这两个基本操作', '实现了线性表从无到有和从有到无', '这样的两个过程',

'主要做的工作就是', '分配内存空间和释放内存空间','当然还需要更改一些必要的信息', '

那接下来还需要实现的基本操作', '是插入和删除', '

那这个地方给的这个描述', '是不是很类似于我们的函数', '这个部分是函数名', '括号里边的部分是函数的参数'

, '那这指明了三个参数**', '第一个参数l指的是线性表', '第二个参数i指的是', '我们要在第二个位置上插入元素', '而第三个元素e指的是我们具体要插入的', '这个元素的**值', '删除操作也是类似的啊', '一个函数名', '然后里边有一些相应的参数', '那接下来还需要实现的基本操作',

'是按值查找按位查找'

'所谓的按值查找', '指的是可以给定一个元素e的值 ', '然后在线性表l2 当中查找', '这个线性表当中', '有没有哪个数据元素', '和我们传入的这个参数e是相同的', '这是暗指查找'

按位查找指的是我们传入一个参数i', '这个i指明了', '我们想要找的是线性表当中的第几个元素', '

最后我们还可以定义一些其他的常用操作', '比如可以定义一个函数length传入l', '然后会返回这个线性表l的长度', '也可以定义一个函数print list', '传入一个线性表l', '然后它会打印输出线性表l当中', '

所有元素的值', '然后最后就是一个判空操作', '传入线性表l', '如果线性表是空表的话'****,'那么呃这个函数会返回true', '如果线性表不空的话', '那么会返回false', '那这些基本操作的具体实现', '我们在之后还会用具体的代码来讲解', '我们在这儿只需要形成一个大体的印象好', '那这个地方要提几个点', '

第一在我们学习任何一个数据结构的时候', '其实其实基本上对于数据结构的操作', '无非就是**创建销毁或者增删改查', '**也就是增加一个数据元素', '或者删除一个数据元素',

'或者改变一个数据元素的值', '或者查询某个数据元素', '大家在学习之后的数据结构的时候', '呃', '也可以自己思考一下',

'对于某一种特定数据结构的创建销毁', '增删改查应该怎么实现', '像这个地方对线性表的插入和删除操作', '不就是增加一个数据元素', '和删除一个数据元素吗', '而下面的这两个操作', '其实就是查询某一个数据元素', '虽

然我们在这儿没有定义啊', '更改某一个数据元素的值这样的基本操作', '但是其实所谓的改的操作', '你在改之前', '不也需要查到你想要改的那个数据元素吗', '所以其实改操作的第一步也是查', '需要先找到你想要改的那个数据元素', '而后面的这些基本操作', '其实就是为了方便编程而实现的', '最核心的还是上面这些基本操作好', '第二个值得注意的点是', '在c语言当中', '如果我们定义一个函数的话', '那么我们需要声明一个函数名', '就是这个东西', '然后在函数名之后需要声明参数列表', '包括参数名和参数的具体类型','但是在我们上面这个地方', '

当我们在描述这些基本操作的时候', '我们并没有指明', '具体的参数类型到底是什么', '所以这个地方给出的这种函数接口', '其实它是具有抽象性的', '比如这儿的e指的是数据元素', '那你的线性表当中存储的数据元素', '可以是存储int型的变量', '也可以是存储某一种struct类型的变量', '所以我们在这个地方描述基本操作的时候', '并没有指明啊这个参数的具体类型', '只有我们用代码来实现这些基本操作的时', '候', '我们才需要啊', '真正的关心这些参数具体是什么类型好',

'比如如果你觉得更改某一个数据元素', '这个操作很常用的话', '那你当然也可以把更改一个数据元素', '定义为一个基本操作', '第四个需要提醒大家的是', '在这儿给出的这些函数名', '还有参数的名字', '

', '你看他这destroy list','你光看它这个函数名', '你就知道它就是要销毁一个表', '你不能说你自己定义的销毁操作', '你取一个函数名叫a', '那谁知道你的a是干嘛的对吧', '当然了', '如果大家在答题的时候', '使用这个地方推荐的这些命名方式的话', '肯定是改卷老师很喜欢看到的好',

'第五个要强调的 点是', '这个地方大家会发现有的函数', '有的基本操作', '它里边传入的这个参数是这种引用类型', '这是c加加里边的写法', '那什么时候需要传入这种引用型的参数', '先给出结论', '一会儿再具体解释', '

如果你对参数的修改结果需要带回来的话',

'那么你就需要传入这种引用型的参数', '

, 'main函数里', '首先定义了一个变量x x的值为一', '然后在这个地方print f输出了x的值', '接下来调用了test这个函数', '把x这个变量作为参数', '传到test这个函数里边', '然后在test里边对x的值进行了修改', '把它变成了1024', '修改之后打印出x的值', '接下来test函数运行结束之后', '又在这个地方再次打印x的值', '运行的结果是这样的', '在调用test之前',

'x的值是一', '而在test函数的内部', 'x的值被改成了1024', '但是test函数执行结束又返回main函数的时候', 'x的值又变成了一',

'所以这个地方','test函数对x的值虽然进行了修改', '但是这个修改的结果没有带回来', '没有带回的main函数', '

这背后的原因是', '在main函数里面定义了一个变量', 'x初始值为一', '然后再调用test函数的时候', '其实test函数里边的这个x是', 'main函数里边这个x的一个复制品', '这两个变量虽然都叫x', '但是在内存当中', '它们其实是两份不同的数据', '所以test函数当中把x的值改成了1024', '改的其实是上面这一份的数据', '所以test运行结束又回到main函数之后', '

这个地方打印出的x值', '其实是这一份的x值', '它依然是一注意体会这句话', '对参数的修改结果没有带回来好', '那再来看一下',

'我们接下来把这个参数改成引用类型', '也就是在参数名前面加一个引用符号', '然后看这边这是运行结果',

在test中把x的值改成了1024', '然后再返回到main函数的时候', '在这儿打印出的x值也是1024', '也就是说', '如果我们把参数改成引用类型', '那么test函数中对参数的修改', '就被带回到main函数当中了', '那简单的理解就是说', 'main函数里面定义了一个变量x', '然后这个变量x作为参数传给了test函数', '而由于这个函数当中啊', '定义的这个参数它是引用类型的', '所以其实test当中他操作的这个参数', '和main函数里边的这个x是同一份数据',

'所以在test当中对x的修改', '也会影响到main函数里边的这个x的值', '那通过这两个例子', '大家应该能够感受到什么叫做', '你需要把对参数的修改结果给带回来', '那这个地方提醒一下',

顺序表

, '基本操作', '从逻辑上看', '线性表的各个元素它是一个有顺序的序列', '各个数据元素之间有先后的关系', '那这种逻辑结构是从我们人类的视角来理解所看到的一些特性', '

我们在计算机当中应该怎么表示这种数据元素之间的逻辑关系呢', '所以从这节课开始', '我们会分别介绍怎么用顺序存储这样的存储结构来实现', '线性表', '怎

么用链式存储来实现', '那这个小节中我们学习的顺序表', '其实指的是用顺序存储方式来实现的线性表', '这个小节我们会学习顺序表的定义', '会介绍顺序表的一些特性', '以及怎么用代码来实现顺序表', '下一个小节我们又会介绍基于顺序存储这种存储结构', '应该怎么用代码具体的实现我们之前所定义的一系列基本操作好的', '那首先来看顺序表的定义', '顺序表指的是用顺序存储的方式来实现的线性表',

顺序存储', '

指的是把逻辑上相邻的数据元素存储在物理上也相邻的呃', '存储单元当中'

这个我们在绪论中提过', '根据这张图很容易理解', '很直观', '这些数据元素之间的前后关系', '通过这种物理内存上的连接关系来体现', '

上一小节中我们强调过呃', '线性表当中的各个数据元素', '它们的数据类型都是相同的', '也就是说每个数据元素它们所占的内存空间是一样大的', '

所以如果顺序表的第一个数据元素', '它的存放地址是这个地址的话', '那么由于顺序表当中各个数据元素它们在物理内存上是连续存放的', '并且每个数据元素它们所占的空间大小都是相等的', '因此它的第二个数据元素所存放的位置', '就应该是这个顺序表的起始地址加上数据元素的大小', '而第三个数据元素存放的位置就应该是它的起始地址', '加上二乘以数据元素的大小', '以此类推', '那我们怎么才能知道一个数据元素的大小到底是多少呢

', 'c语言当中提供了一个很方便使用的关键字'**, '叫size of size off', '打个小括号', '然后里边传入你的顺序表当中存放的这个数据元素的数据类型', '比如如果你的顺序表当中存放的是一个一个的整数', '那么只要你用size of里边填入int', '就可以得到一个int型的整数', '在这个系统当中', '它占多大的内存空间', '**那在c语言当中', '很多情况下', '一个int型的变量它是占四个字节', '当然你的顺序表当中还可以存放啊', '其他更复杂的数据', '比如说可以存放结构类型的数据', '像这个地方我们定义了一个叫customer的结构', '里面存了两个整数', '分别是numb和people', '那么两个整数每个整数占四个字节', '所以customer这种数据类型', '它占的内存空间大小就

静态分配

看顺序表的第一种实现方式叫做静态分配呃', '所谓静态分配就是指使用这种大家最熟悉的数组的这种定义方式', '来实现一个顺序表', '当然这是一个静态的数组', '也就是说这个数组的长度大小一旦确定了之后', '它就不可以改变', '这是静态数组的特点', '我们的顺序表用这样的数据类型来表示', '里面定义了一个静态数组长度为max size啊', '这是我们宏定义的一个常量', '另外还定义了一个叫lance的变量', '用于表示当前这个顺序表', '它的实际长度到底是多少', '那max size的值决定了顺序表它最多可以存放几个数据元素', '而length的值表示的是当前这个顺序表当中已经存入了多少个元素', '如果从内存的视角来看的话', '当你声明了一个data数组的时候', '那么其实就是在内存当中开辟了一整片的连续空间', '这一整片的连续空间总共可以存放十个数据元素', '我

所以如果知道了顺序表的起始存放位置', '也就是它的第一个数据元素的存放地址', '那么后面这些数据元素的存放地址', '是不是就可以很方便地用size of这个关键字马上就可以得到', '马上就可以算出来', '好的那接下来

们这儿的代码当中', '数据元素的类型用type来表示', 'alan其实就是element', '就是元素的缩写', '数据元素的类型可以是int型', '可以是你自己定义的某一些更复杂的struct类型', '这个具体要看你要用你的顺序表来存什么', '那这个地方我们用alan type来表示', '只是为了让它更具有通用性', '大家如果自己写代码实现的话', '那么你的数据元素类型呃', '它具体是什么类型', '你把这个alex给替换掉就可以了', '那我们把顺序表起名为sq list', '这儿的sq指的是sequence'

顺序表', '下'对这个顺序表进行初始化', '其实这个函数就是我们上一小节当中提到的基本运算的第一个好', '那既然main函数调用了in it list', '所以接下来就会开始执行这个函数里面的代码', '首先是一个for循环', '

这个for循环做的事情是把data这个数组当中', '所有的这些数据元素的值都置为零', '也就是给各个数据元素设置一个默认的初始值', '当然这个设置默认初始值的步骤其实是可以省略的',

'这个我们一会儿再来解释好', '那除此之外', '还需要把length的值置为零','因为刚开始顺序表当中没有存入任何一个数据元素', '所以此时顺序表的当前长度应该是零', '那这就是对顺序表的一个初始化工作好

', '那接下来要探讨的问题是', '如果不给这个data数组设置一个默认的初始 值的话', '会发生什么情况', '我们把这个部分的代码给去掉', '也就是说在对一个顺序表进行初始化的时候', '只是设置了它的length变量的值', '那我们在main函数里添加了一个for循环', '把data这个数组全部给打印出来', '那打印的结果是这样的', '可以看到data这个数组前面这些数据元素啊', '它都是零',

'这很正常对吧', '但是最后这两个数据元素看一下是两个很奇怪的值', '如果大家在自己的电脑上实现这一段代码的话', '那么大家的电脑上打印出来的啊', 'data这个数组当中各个元素的值跟我的还会不一样', '那产生这种奇怪现象的原因是内存当中会有遗留的脏数据', '也就是说当我们在声明这个顺序表的时候', '

虽然系统在背后给我们分配了这么一大片的内存空间', '但是这一片内存空间之前存的是什么数据', '其实我们并不知道', '所以如果我们不给这些呃数据元素设置默认值的话', '那么呃会因为之前遗留下来的脏数据', '而导致我们的这个数组当中出现一些奇怪的数据', '不过刚才我们说过', '给各个数据元素设置默认值', '这一步其实是可省略的',

'原因在于我们在这个main函数里打印顺序表当中的内容', '这个操作其实是违规的', '我们就不应该按照这样的方式来访问顺序表', '因为顺序表当中不是定义了一个变量叫length', 'length表示的是它当前的长度', '所以当我们在访问顺序表当中的各个数据元素的时候', '不应该从第一个元素访问到最后一个元素', '而应该是访问到顺序表', '

当中当前实际已经存储的啊最后的一个元素', '那由于刚开始length的值是零', '所以如果用这种稍微正规一些的写法的话', '那么这个for循环当中的语句是不会被执行的', '所以为什么说我们可以省略啊', '给各个数据元素设置默认值这一步', '那是因为如果按正常的访问方式的话', '那么我们其实并不应该访问啊', '大于顺序表实际长度的那些数据元素', '当然了', '其实更好的做法应该是使用基本操作来访问各个数据元素', '大家可以回顾一下', '上个小节我们提到过', '我们应该实现一个基本操作','就get这个基本操作实现的事情', '是把l这个线性表当中的第二个元素给取出来 ', '所以其实使用基本操作来访问是最好的一种方式', '那这个地方想让大家重点体会的是这个脏数据是怎么回事', '那既然内存当中会有脏数据', '所以当我们声明length这个变量的时候', 'length的初始值把它设为零', '这一步是不是就肯定不能省略', '因为你无法预知在这一小片的啊', '内存区域内之前存放的到底是什么数据', '

那有的同学可能会说', 'c语言不是会自动给int型的变量设置一个默认初始值为零吗', '那其实这个默认初始值设置为多少', '这是编译器做的事情', '如果换一个c语言的编译器', '也许他就不会帮你做这种初始化的工作', '所以当我们在声明一个顺序表的时候', '刚开始把它的length值设为零', '这一步是必须做的好的','那么通过刚才的代码', '相信大家对顺序表的静态分配这种实现方式已经有了更深入的理解', '那这种实现方式的精髓在这个地方', '

就是要定义一个静态的数组来存放你的数据元素', '

那接下来要思考的问题是', '如果你声明的你刚开始声明的这个

数组的长度不够了', '它存满了怎么办', '

那遇到这种情况的话', '给大家一个建议', '就是可以直接放弃治疗', '因为这种静态数组的长度', '只要你刚开始声明了', '那之后**', '它的容量就不可以再改变**', '也就是说给这个顺序表分配的存储空间是不可变的', '是静态的', '

那有的同学可能会说', '那既然这样的话', '你刚开始就申请一大片连续的存储空间', '把这个数组的长度设大一点不就行了吗', '那如果采用这种方式的话', '存在的问题就是很浪费', '你想假如你的这些数字你设置了1万的长度', '但是最后你只用了十个', '那那这样岂不是很浪费内存资源吗', '所以这种方式是不太机智的', '那从这个地方大家就应该能够体会到', '静态分配这种实现方式', '它存在一定的局限性', '

主要就是这个顺序表的大小容量它是不可调的', '无法更改', '那如果要让顺序表的大小可变的话', '那我们

动态分配

可以采用动态分配的这种实现方式', '如果采用动态分配来实现顺序表的话', '那么我们需要定义一个指针', '

个指针是指向 了顺序表当中的第一个数据元素', '另外由于动态分配方式当中', '顺序表的容量大小是可以变的', '所以我们需要在这增加一个变量叫max size', '表示顺序表的最大容量是多少', '

那除了最大容量之外', '当然也需要用length这个变量来记录顺序表的当前长度', '也就是说此时顺序表当中实际上已经存放了多少个数据元素',

'c语言当中提供了malloc和free这两个函数', '来分别实现动态的申请一片内存空间和释放一片内存空间', '这两个函数是十分重要的好',

'那具体来看一下my log函数的原理', 'my lock这个函数它所实现的事情是会申请一整片的啊', '连续的内存空间', '那这一整片的内存空间它肯定有个起始的内存地址', '所以mlock函数执行结束之后',

'它会return会返回一个指向这一整片存储空间开始地址的这个指针', '那由于这一片存储空间是用于存放我们一个一个的数据元素的', '所以在这个地方我们需要把mlock函数返回的这个指针', '把它强制转换成你所定义的这个数据元素的数据类型所对应的指针', '

比如如果你的顺序表是用于存放整数 的', '也就是说数据元素是int类型', '那么当你在使用malloc函数的时候啊', '就需要把这个type把它换成int', '那mo函数返回的这个内存的起始地址的这个指针', '我们需要把它付给顺序表当中的data这个指针变量', '也就是说data这个指针是指向了这一整片存储空间的起始地址',

'那第二个需要注意的点', '既然my log函数是申请一整片的连续存储空间', '那么你到底要申请多大的空间呢', '这就这个是由malloc函数的这个参数所指明的', '看一下左边这个size of element type', '之前我们讲过这个部分的式子', '得到的结果就是你的一个数据元素', '它所占存储空间的大小', '如果你的数据元素是int类型', '那么它所占的大小就应该是四个字节', '

然后第二个部分它要乘以in it size', 'in it size', '指的是这个顺序表', '它刚开始初始的长度', '那在这儿我们把它呃定义为一个常量是十', '所以这一整个式子计算得到的结果就应该是存放十个你的int型变量', '所需要的存储空间大小', '那这就是malloc函数',

'那如果学过c加加的同学', '可以用new和delete这两个关键字来实现类似于malloc和free的功能', 'new和delete涉及到面向对象相关的一些知识点', '而我们为了照顾到更多的跨考的同学', '所以我们在之后的学习当中会更多地使用malloc和free这两个函数', '好的',

'那接下来还是用一个具体的代码来看一下这个顺序表的动态分配', '在背后发生了一些什么事情', '

我们在这儿定义了一个顺序表

', '这个顺序表的数据元素类型是int类型', '那data这个指针指向的顺序表当中的第一个数据元素', '然后我们实现了一个函数init list', '用于初始化一个动态分配方式实现的顺序表','然后再实现一个函数', '

用于动态的增加这个顺序表的长度', '

然后我们在main函数里调用这些相关的操作', '一会儿我们来分析一下背后的过程', '那需要注

意的是', 'in at least这里边使用到了mk函数', '然

后增加动态数组的长度', '或者说增加顺序表长度', '这个函数里边又使用到了malloc和free这两个函数',

'malloc和free包含在了这个头文件当中', '所以如果大家自己写代码', '需要使用到mlock和free

这两个函数的话', '需要include这个头文件好', '那接下来分析一下这段代码运行的过程**', '**

先在main函数里声明一个顺序表', '执行完这一句代码之后', '其实计算机会在内存当中开辟这样的一小片空间', '这片存储空间存放了啊', '这个顺序表当中的这几个变量', 'max size表示的是顺序表的最大容量', '然后length表示的是当前这个顺序表当中有几个数据元素', '而data它是一个指针类型的变量好', '那接下来会开始执行我们定义的这个基本操作', '也就是初始化顺序表',

'在这个函数的第一句会调用malloc函数**', 'malloc函数会申请一整篇连续的存储空间', '这片存储空间的大小应该是能够存得下十个int类型数据的啊', '这样的一个大小', '**

接下来my log函数会返回一个指针', '我们把这个指针的类型把它转换成和这相统一的指针类型', '然后把malloc返回的这个指针的值把它赋给d',

'那之前我们说过', 'malloc返回的是这一整片连续存储空间的起始地址', '所以在执行完这句代码之后', 'data这个指针应该是指向了这个位置 ', '再次强调需要把malloc返回的指针', '把它转换成我们这儿定义的同类型的指针好', '那除了data之外', '我们还需要把呃顺序表的当前长度nice把它设为零', '然后把顺序表的最大容量把它设置为这个初始值', '和这个地方保持一致好',

'那接下来我们省略了一些代码', '可以往这个顺序表当中插入数据', '把它都给填满', '那此时next的值就应该是十', 'max size的值也应该是十', '再往后如果还想存入一些数据的话', '这个顺序表的大小是不是就不够了',

'所以在这个地方我们实现了一个函数', '动态的增加这个数组的长度', '或者说增加这个顺序表的长度', '那这儿有个参数l这个参数表示的是我需要拓展啊多少的长度', '那我们这儿传入五', '也就是说想要让这个顺序表可以再多存五个数据元素好', '那第一

句我们定义了一个指针p', '把顺序表的data指针的值赋给这个p', '也就是说这个p指针和data是指向了同一个位置', '

接下来要调用malloc函数', 'my log函数所做的事情是申请一整片的内存空间', '这片空间的大小应该能够存得下当前的所有的这些数据元素','同时还可以再多存五个啊', '新的数据元素',

'当然这还需要乘以每一个数据元素的大小', 'size of element type', '也就是需要使用size of这个关键词', '这样的话就意味着这开辟了一片新的空间', '这片空间可以存15个元素', '以前只能存十个', '现在可以多存五个好', '

那由于mlock他申请的内存空间是另一片内存空间', '而这一片内存空间此时啊并没有往里面存任何数据', '接下来我们让data这个指针指向新的这一片空间', '然后再用一个for循环', '把以前这一片内存空间的这些数据把它给挪过来',

'然后由于顺序表的最大容量增加了这么多', '所以我们需要把max size的值把它加五', '也就是变成了15',

'最后要做的一件事情是调用free函数', 'free函数会把p这个指针所指向的这一整片的啊存储空间给释放掉', '把它归还给系统','那由于p这个变量它是一个局部于这个函数的变量', '所以当这个函数执行结束之后', '存储p这个变量的这些内存空间会被系统自动的回收', '所以这就用my lock实现了一个呃动态数组的扩展', '或者说顺序表的扩展', '那由于我们需要把数据复制到这个新的区域',

'因此虽然动态分配这种方式可以让顺序表的呃大小能够灵活地改变', '但是其实时间开销还是很大的', '另外c语言基础好的同学可能知道一**个叫做realloc的函数', '**这个函数其实也可以实现这边我们所提到的这一系列的过程和功能',

'但是realloc这个函数其实它调用的过程当中会有一些意想不到的坑', '所以我建议大家最好还是自己使用malloc和free这一对函数', '并且用这两个函数更能理解我们这个动态分配', '它背后所发生的这些过程', '好的', '那么我们介绍了顺序表的两种实现方式','第一种是静态分配', '第二种是动态分配',

'那不管是用哪种方式实现顺序表', '都具有这样的一些特性', '

第一叫随机访问', '也就是说可以在常数级的时间复杂度内就可以找到第二个元素', '原因就在于顺序表当中各个数据元素的存放位置是连续存放的', '因此只需要知道第一个数据元素的存放地址', '那么后面这些数据元素的存放地址就可以马上算出来', '所以可以在常数集的时间内找到第二个元素', '那对应我们的代码其实就是我们用数组', '然后给一个数组下标', '就可以直接找到第二个元素', '当然其实系统在背后还做了计算地址等等这一系列的操作'

, '那顺序表的第二个特点是存储密度高', '每个存储节点只存储数据元素本身',

'但如果我们采用链式存储的话', '除了存储数据元素本身之外', '还需要耗费一定的存储空间来存放指针这样的信息', '所以这是存储密度高的意思',

'第三个特点是拓展容量不方便静态分配', '这种方式直接就是不可以拓展容量',

'而动态分配这种方式虽然可以拓展容量', '但是由于我们需要把数据给复制到新的区域', '所以其实时间复杂度也比较高', '第四个特点是插入删除操作不方便', '需要移动大量的元素', '

那这个特性我们会在下一个小节当中结合具体的代码', '让大家有更直观的体会', '好的那这个小节我们介绍了顺序表的定义', '所谓顺序表其实就是用顺序存储的方式实现的线性表', '顺序存储的存储结构就决定了啊', '逻辑上相邻的数据元素在物理上也相邻', '

那我们介绍顺序表的两种实现方式', '分别是静态分配和动态分配', '静态分配的代码很好写', '就是定义一个大家很熟悉的数组'

, '而动态分配里边我们需要使用到my loc和free这两个函数', 'mo函数可以申请一整片的内存空间', '如果当前顺序表的容量不够的话', '那么我们可以用malloc再申请一片更大的存储空间', '然后把数据元素复制到这个新的区域', '并且用free函数释放掉原来的这个内存区域', '把它归还给系统', '这个函数在考研当中是十分重要的', '大

家一定要自己动手写一写', '熟悉它的用法', '最后我们介绍顺序表的几个特点', '最重要的特点是这个随机访问的特点', '可以在o一的时间复杂度内找到第二个元素', '这个美好的特性就是由于数据元素在内存当中连续存放而导致的', '下一个小节当中', '我们会介绍呃怎么实现顺序表的插入和删除这两个基本操作', '到时候大家会更直观地体会到什么叫插入和删除数据不方便', '好的', '那以上就是这个小节的全部内容']

小结

顺序表的插入和删除

, '用代码定义一个顺序表', '并且能够知道顺序表应该怎么完成', '初始化的工作', '那当一个顺序表刚开始被建立的时候', '它其实是一个空表', '也就是说里边并没有存任何的数据元素', '那这一小节中',

'我们会学习顺序表的两个基本操作', '我们会分别介绍怎么用代码', '实现这个基本操作', '并且会分析啊这个代码的时间复杂度好', '那

首先要学习的是插入这种基本操作', '插入操作要实现的事情是', '

往线性表l2 当中的第i个位置上', '插入指定的元素e', '那这第二个位置指的是位序', '也就是从一开始的', '那',

'假设我们用静态分配方式', '实现了一个顺序表', '那么这个顺序表总共可以存十个元素', '假设在某一个时刻', '这个数据结构当中', '包含了这样的五个数据元素', '那这些数据元素在内存当中', '就应该是这么存放的', '会占用顺序表的前五个位置', '那由于存放了五个数据元素', '所以此时这个顺序表的长度应该是五', '此时如果要进行一个插入的操作', '往这个线性表的第三个位置', '插入一个数据元素c的话', '那逻辑上来看', '进行这个操作之后**', 'c就变成了b的后继节点', 'd的前驱节点'**

, '由于我们的这个线性表', '是用顺序表的方式实现的', '所以需要用存储位置上的相邻关系', '来体现这种数据元素之间的逻辑关系',

'因此如果要在第三个位置插入元素c的话', '那么需要把后面的这三个元素', '都依次往后移 ', '然后再把c这个元素插到第三个位置', '所以如果我们在顺序表的第二个位置', '插入一个元素的话', '那么这个顺序表当中', '第二个位置以及第二个位置以后的', '那些数据元素都得往后移一位', '接下来看一下怎么用代码实现这个事情', '

这个小节中', '我们写的代码都是基于静态分配的', '这种啊顺序表来实现的', '好来看一下', '我们在这定义了一个顺序表', '这个顺序表当中存放的数据元素', '都是int类型', '也就是存放一个一个的整数', '然后这个地方我们用函数实现了插入操作', '

在main函数里我们会声明一个顺序表', '并且对它进行初始化的操作', '并且这个地方我们省略了一些代码', '这些代码会往顺序表当中啊存入一些数据', '假设此时存入了12456', '这样的几个数据元素', '所以此时顺序表的长度应该是五, '

接下来会调用我们这儿的这个函数', '来实现插入操作', '这个函数实现的事情是', '往第三个位置插入数据元素', '三好', '那之前我们说过', '首先要把后续的这些数据元素', '都分别往后移对吧', '所以在这儿我们使用了一个for循环', '刚开始这这个变量的值等于顺序表的长度', '也就是等于五', '那只要g大于等于i', '也就是只要它大于等于三的话', '这个循环就会一直继续啊', '每一轮循环结束之后', 'g的值会减一好', '那首先来看一下',

'第一次执行这个循环里面的语句的时候', 'j的值是五对吧', '**所以这句代码做的事情是把data 4的数据', '把它放到data 5这个位置', '也就是把这个数据元素往后挪一位好', '那执行了这一句之后', 'j的值是不是会进行减减的操作', '这就变成了四对吧', '所以下一轮循环做的事情是', '会把data 3这个数据元素', '把它放到data 4这个位置', '**所以第二轮循环会把五这个数据元素', '往后挪一位', '那第三轮循环也是一样的', '会把四这个数据元素往后挪', '

一位跨考的同学', '可以自己一步一步分析一下啊', '这个循环它到底是怎么执行的', '他最后停在了什么地方好', '那这个循环结束之后', '我们就可以往第三个位置插入', '我们的数据元素', '也就是三这个数字', '这个地方大家一定要注意', '我们这儿的函数参数', 'i表示的是这个线性表的位序', '它是从一开始的', '但是实际对应到我们的数组的时候', '数组的下标是从零开始的', '所以我们要把数据元素放在第三个位置', '实际上应该是要把它放在数组下标为二的', '那个地方', '这个自己做题写代码的时候一定要注意好', '那接下来由于多了一个数据元素', '所以顺序表的长度length就应该加一', '那到此为止',

'我们是不是就实现了插入这个基本操作', '我们可以让我们的队友', '让其他人很方便地通过我们的这个函数', '来使用我们自己定义的数据结构', '不过要提醒大家的是', '如果你的队友在使用你给它定义的', '这个函数的时候', '它传入的参数出现了一些问题的话', '那么这段代码的运行就会出错', '比如此时你的队友调用了你的这个函数', '他想往第九个位置插入三这个数据元素', '大家可以自己暂停', '分析一下这个代码怎么运行', '当这段代码运行完了之后', '三这个数据元素会被插到八这个位置', '但是中间这个地方空了', '这其实是不正确的对吧', '我们的顺序表当中',

健壮性'

它的各个数据元素', '一定是必须一个一个相邻的存放的', '所以你看这段代码其实它是不够健壮的', '怎么避免这个问题呢', '很简单', '我们只需要一个条件判断的语句', '可以判断一下这个i的值是否合法', '那i的合法值应该是多少呢', '应该是从一开始', '然后到length加一结束对吧', '如果此时有人想往顺序表的第九个位置', '插入元素的话', '那由于这个i的值', '已经超出了它的合法范围', '所以我们就不应该进行', '后续的这一系列操作好', '那再想一下', '除了i的值不合法之外', '是不是', '当你的顺序表如果已经存满了的时候', '其他人想要再插入数据', '你也应该把他拒绝掉对吧', '所以当别人调用你定义的这个', '基本操作的时候', '你还应该在代码里边检查', '此时这个顺序表是否已经存满了', '如果存满了', '那么就不应该往里边继续插入数据好', '那大家站在使用者的角度来考虑', '如果你定义的这个基本操作', '让其他人使用', '其他人想插入某一个数据元素', '但是此时由于某些条件不满足', '你又不能让它插入这个数据元素的话', '那调用你这个函数的那个人', '他是不是应该得到你的这个代码的', '某一些反馈', '至少他得知道他这次调用的这个插入操作', '到底是操作成功了还是失败了对吧', '所以其实在实际写代码的时候',

'除了这个代码逻辑本身要正确之外', '其实大家还应该有一种意识', '就是你的这个代码让别人用起来用的很爽', '那可以怎么做呢', '我们可以让你的这个插入操作', '返回一个布尔型的变量', '刚开始需要先进行i这个值的合法性判断', '如果i这个值小于一', '或者大于lx加一的话', '那么说明此次他想要插入的这个位置', '本身就不合法', '那在这种情况下给它返回一个force', '那这样的话', '这个函数的调用者在接收到false', '这个返回值的时候', '它是不是就可以知道诶', '此次调用失败了', '然后他就可以根据你的这个反馈去检查', '他自己的代码是不是出现了问题', '对吧好', '那另一个条件', '如果此时这个顺序表已经存满了', '那在这种情况下', '这次的插入操作也应该是失败的', '所以也需要返回一个false', '那这两个条件都满足之后才可以进行', '刚才我们说的那一系列的操作', '就是先把后续的那些元素都依次往后移', '最后再把此次想要插入的那个元素', '插入到相应的那个位置', '在插入成功之后再给调用者返回一个true', '给他一个反馈', '那用这样的方式定义一个插入操作', '是不是使用者使用起来也很爽', '同时这个代码也有健壮性啊', '那这么写的代码就是好代码', '按照这样的代码逻辑', '如果此时顺序表已经满了', '但是还有人调用了你这个函数', '想要插入一个数据元素的话', '那他的这个操作就会被拒绝好', '所以虽然这段代码逻辑非常简单', '但大家可以体会一下', '如果你自己啊', '此时真的是在进行一个团队开发', '一个大型的项目的话', '那么你的这个代码怎么让别人用起来爽', '并且别人用你的代码还不容易出错', '这些思想意识', '应该是从刚开始学习的时候啊', '就引起大家的注意的'

时间复杂性

, '好的', '那接下来我们来快速的分析一下**', '插入这种基本操作', '它的时间复杂度是怎么样', '那在绪论中我们学到过呃', '要分析时间复杂度的话', '应该关注这一段代码当中最深层循环的啊', '这个语句在插入操作当中只有这个for循环', '所以我们来看一下这个for循环', '循环的次数和问题规模n之间的关系', '这儿的问题规模n指的是线性表的表长',** '或者说这个

顺序表的表长好', '那之前提到过时间复杂度分为最好', '最坏和平均这样的三种情况对吧',

'那什么情况下时间复杂度会最低呢', '如果此时我们把数据元素插入到顺序表', '表匪的位置的话', '那其他数据元素是不需要移位的', '也就是for循环的次数是零次', '那这种肯定是执行最快的一种情况', '也就是当i等于length加一', '就意味着', '此次我们是要插入到这个顺序表的', '最后面的一个位置', '这种情况下是不是代码是这么执行的', '一直往下执行这个for循环', '是不是就不用循环', '而其他的这些语句都只需要执行一次', '所以这种情况下', '只需要常数集的时间就可以完成这个操作', '

那最好的另一个极端是最坏', '

如果此时我们是要把新元素', '插入到表头的位置的话', '那么就需要把原有的这n个元素', '全部都往后移动',

'也就是for循环或循环n次', '所以最坏时间复杂度应该是大on', '这样的数量级好

, '最后再来看平均时间复杂度怎么算呢', '

我们假设如果此次要插入的新元素', '插入到任何一个位置的概率都是相同的', '也就是说', '此次传入的这个参数i取得123', '一直到练习加一', '取得这个合法范围内的任何一个数字', '概率都是相同的', '也就是总共有n加一个位置是是新元素', '有可能插入的', '因此这个元素插入到任何一个位置的概率', '都应该是n加1/1这么多好', '那假设此次要插入的是第一个位置的话', '那根据之前的分析', '是不是需要把后面的n个元素', '先全部循环的往后移位对吧', '因此i等于一的时候需要循环n次', '而当i等于二的时候', '除了第一个元素之外', '后面的n减一个

删除

那接下来我们再来看一下', '顺序表的删除操作怎么实现',

'如果要删除一个元素的话', '那么我们需要把这个元素后面的那些元素', '都依次往前移一位', '同时要把length的值减一', '

那用代码实现的话就是这个样子',

'这个删除操作当中有三个参数', '第一个是要删除哪个顺序表', '第二个是要删除这个顺序表当中的', '第几个数据元素', '第三个参数注意它是一个引用型的参数', '

用这个参数把此次删除的数据元素返回好', '来看一下具体的过程', '假设通过之前的一系列执行', '已经建立了一个这样的顺序表', '它里边存了总共六个数据元素好', '

那如果此时想要使用这个基本操作', '删除一个数据元素的话', '那首先需要定义一个和你的顺序表当中', '存储的这些数据元素同类型的一个变量', '那我们的这个顺序表当中存储的数据元素', '类型都是int类型', '所以我们定义一个int型的变量e', '并且给它设置一个初始值-1', '

那声明了这个变量e', '就意味着内存当中会开辟一小片的空间', '用于存放e这个变量相关的数据', '由于我们给他设了一个初始值', '所以这片区域里边存储的数据内容是-1', '这个值好',

'接下来调用删除这个基本操作',

'要删除l这个顺序表当中的第三个元素', '然后把此次删除的那个元素', '用e这个变量给返回',

'那首先在我们的这个删除操作当中', '我们进行了一个i的合法值的判断', '因为此时可以被删除的数据元素', '肯定是已经存在的', '这些数据元素当中的某一个对吧', '所以如果i的值落在了这个区间之外的话', '那么就应该给他return一个force', '也就是给这个函数的使用者一个反馈', '告诉他你的这个删除操作失败了', '所以在这个地方', '我们用一个if语句', '来接收这个函数的返回值', '如果他此次返回了false的话', '那说明我们的这次调用就已经调用失败了', '那由于此时想要删除的是第三个元素啊', '所以这个a的值是合法的', '因此接下来会执行下面的这一句', '这些代码会把此次要删除的这个', '数据元素的值', '把它复制到e这个变量所对应的', '这个内存区域当中好', '那接下来就是执行一个for循环', '把后面的这些数据元素依次往前移一位', '最后next的值减一', '也就是从六变成了五', '那由于这个删除操作成功了', '所以会给啊这个函数的调用者返回一个true', '也就是这个if的条件是满足的', '所以接下来会执行这个print语句', '打印出这样的一个结果好', '那大家值得注意的是这样的两个地方',

'首先我们定义的这个删除操作e这个变量**', '它是引用型的变量', '我们加了这个引用符号',** '由于加了这个引用符号', '所以在这个函数里边处理的这个变量', 'e其实和main函数里面定义的这个变量', 'e在内存当中其实对应的是同一份数据', '而

如果这个e变量不是引用型', '把这个引用符号去掉的话', '那么在main函数里边', '它声明了一个局部与main函数的变量e', '并且又调用了这个删除的函数', '那由于这个参数不是引用类型的', '所以这个函数里边它所处理的这个变量e', '其实是main函数里边', '这个变量e的一个复制品', '这两个变量虽然名字都是e', '但是在内存当中', '它们对应的其实是不同的两份数据', '所以如果我们没有加这个引用符号的话', '那这个函数里边','把此次删除的数据元素的值赋给变量e', '其实是付给了这个位置对吧', '而main函数里边的这个变量e', '其实它的值依然是保持-1没变', '所以如果这个参数去掉引用符号的话', '那么在这个地方打印的e的值', '应该还是保持-1对吧', '所

以在刚开始学习数据结构的时候', '一定要注意理解啊', '这些加了引用符号的参数', '为什么他要加引用符号', '当然包括前面l这个参数也就这个顺序表', '它的前面也加了引用符号', '如果这个参数l不加引用符号的话', '那么main函数里面定义的这个顺序表', 'l其实是对应的这一份这一坨数据对吧', '如果去掉这引用符号', '那么在这个删除函数里边', '处理的所谓的这个l', '其实应该是这堆数据的一个复制品', '同样的道理', '在这一堆数据的复制品上面', '执行一系列删除相关的这些逻辑操作', '但是返回麦函数之后', '麦函数里面定义的这个顺序表l', '其实它的数据依然是没变的', '对吧好', '

所以这是大家需要注意的一个地方', '另一个地方跨考的同学需要注意', '我们在进行删除操作的时候', '把这些元素依次的往前移', '一位是先移动前面的元素', '再移动后面的元素', '是这样的一个移动方式', '这是for循环里面的逻辑', '但是在我们的插入操作当中', '当我们需要把元素往后移的时候', '我们是先把后面的元素先往后移', '然后再移前面的元素', '这个问题跨考的同学要注意好', '

那接下来我们来分析删除操作的时间', '复杂度', '同样的啊', '

在这个问题当中', '所谓的问题规模n指的是线性表 ', '或者说顺序表的表长', '那其实删除操作和插入操作是非常类似的', '如果我们删除的是最后一个元素的话', '那么其余的元素是不需要移动位置的', '

也就是这个for循环的循环次数是零次', '因此如果我们删除的是最后一个元素的话', '那这就是最好的情况', '只需要在常数集的时间内就可以啊', '运行结束', '

那最坏的情况应该是删除表头元素', '这种情况下需要把后续的n减一个元素', '全部依次往前移一格', '而每移动一个元素就会多一次循环', '所以如果i等于一', '也就是删除第一个元素', '删除表头元素的话', '那么循环次数就应该是n减一次', '所以最坏的情况', '时间复杂度应该是on这个数量级的

', '最后再来看平均情况', '同样的', '我们假设删除任何一个元素的概率', '是相同的', '然后i的合法值范围应该是一到length', '也就是一到n', '因为总共有n个元素嘛', '你要删的肯定是这n个元素当中的其中一', '个', '并且删除每一个元素的概率都是n分之一', '这么多', '我们用p来表示好', '那如果i等于一', '删除的是第一个元素的话', '那么需要循环n减一次', '如果删除的是第二个元素的话', '那么需要把第二个元素之后的n减', '二个元素都依次往前移一位', '也就是需要循环n减二次', '那之后的以此类推', '如果i等于n', '也就是此次删除的是最后一个', '数据元素的话', '那么循环的次数就应该是零次', '因此需要循环n减一次', 'n减二次啊', '一直到循环一次', '循环零次', '他们的概率都是p', '那我们把循环的次数和呃', '每一种循环次数发生的概率', 'p进行一个相乘相加', '就可以得到一个平均情况下的啊', '循环次数二分之n减一', '那二分之n减一', '应该是oon这样的一个数量级', '所以删除操作的平均时间', '复杂度也是o n这么多好', '那这个小节我们学习了', '怎么实现顺序表的插入和删除', '

这两个基本操作', '由于顺序表要求逻辑上相邻的元素', '在物理上也相邻', '所以如果我们想要在某一个位置', '插入一个新元素的话', '那么它之后的那些元素都得呃依次后移', '同理如果删除某个月数据元素的话', '那么那么后面的那些数据元素', '都得一次前移', '当然大家在写代码的时候', '别忘了更改length', '这个值', 'length表示的是呃', '顺序表当中此时存放了几个数据元素', '那大家在做题或者考试的时候', '一定要注意审题', '有的题目可能是告诉你说', '要删除第二个数据元素', '而有的题目也有可能告诉你', '说是要删除数组下标为i的数据元素', '那位序是从一开始的', '而数组下标是从零开始的', '所以做题的时候一定要注意这个小细节', '别在这种地方丢分', '另外你写的这个代码要有健壮性', '所以你需要对一些必要的条件进行判断', '在学习之后的一系列算法', '甚至是在以后大家呃实际实习工作的时候', '都一定要注意这个问题', '你的代码一定要足够健壮', '同时还要能够让别人很方便地使用', '那跨考的同学', '可能在写移动数据元素的for循环的时候', '也许会出现问题', '建议写代码写的很少', '甚至没有写过代码的同学', '自己在稿纸上写一遍', '实现这个插入和删除操作', '然后最后大家一定一定要注意理解', '为什么有的参数是要加引用的', '为什么有的没有', '那像代码健壮性', '还有参数加引用', '这些问题', '我们会在之后的讲解当中提的越来越少', '所以同学们一定要', '在刚开始接触这些简单代码的时候', '就把这些很重要的问题一遍一遍的理解', '把它捋清楚', '真正的吸收内化好的', '那么以上就是这个小节的全部内容

相关推荐
一只积极向上的小咸鱼25 分钟前
PyTorch 和 Python关系
人工智能·pytorch·python
m0_748255021 小时前
python的sql解析库-sqlparse
数据库·python·sql
小爬虫程序猿1 小时前
衣联网的商品列表页面结构是怎样的?
开发语言·爬虫·python
dlhto2 小时前
Ollama+ WebUI 部署deepseek-r1
linux·python·语言模型
东东oyey2 小时前
Prompt 工程
python·llm·prompt·提示词工程
Doopny@2 小时前
含k个3的数(信息学奥赛一本通-1090)
数据结构·算法
九溪弥烟、3 小时前
python编写的一个打砖块小游戏
开发语言·python·pygame
stars3 小时前
搞定python之三----序列、字典及集合
开发语言·python
Matrix703 小时前
Scala编程_实现Rational的基本操作
开发语言·python·scala
qq_257379593 小时前
python基础-字符串速查笔记
开发语言·笔记·python