数据结构和算法学习笔记一:绪论和基本概念
Posted movin2333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构和算法学习笔记一:绪论和基本概念相关的知识,希望对你有一定的参考价值。
一.绪论
说明:本文及之后文章是个人学习数据结构和算法的笔记,学习资料为小甲鱼的数据结构和算法(https://www.bilibili.com/video/av21828275)。我觉得这个课程还比较有趣,课程中代码使用c实现,我会尝试使用C#实现并记录在笔记中。
1.数据结构的概念:一门研究非数值计算的程序涉及问题中的操作对象,以及它们之间的关系和操作等相关问题的学科。通俗来说,程序设计=数据结构+算法,数据结构就是数据元素相互之间存在的一种或多种特定关系的集合。
数据结构可以分为逻辑结构和物理结构。逻辑结构指数据对象中数据元素之间的相互关系,物理结构指数据的逻辑结构在计算机中的存储形式。计算机中的数据结构主要探讨逻辑结构,物理结构探讨较少。
数据的逻辑结构可以基本分为集合结构(元素相互之间没有关系)、线性结构(元素之间线性排列)、树形结构(元素排列呈树状或金字塔型)、图形结构(元素之间多对多关系,排列成网状)。
数据的物理结构主要探讨数据的存储形式,基本有顺序存储(内存连续)和链式存储(内存不连续,数据记录上下游数据的地址)两种。
2.算法的概念:解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
算法的特征:
1)输入:算法具有0个或多个输入
2)输出:算法至少有一个或多个输出(运算结果必须反馈出来),输出可以是打印值也可以是返回值
3)有穷性:算法在执行有限步骤后会自动结束,不会出现死循环
4)确定性:算法的每一步都要有确定的含义,没有二义性;算法在一定条件下,只有一条执行路径,相同输入只能有唯一的输出;算法的每个步骤都必须精确定义,没有歧义
5)可行性:算法的每一步都必须是可行的(可以在执行有限次数后完成)
算法程序设计的要求:
1)正确性:没有语法错误;对于合法输入能够产生满足要求的输出;对于非法输入能够产生满足规格的说明;对于故意刁难的测试输入都有满足要求的输出结果
2)可读性:算法程序必须便于人去阅读、理解和交流
3)健壮性:当输入数据不合法时算法也能作出相关处理而不会产生异常、崩溃或其他莫名其妙的结果
4)时间效率高和存储量低:设计算法时尽量使得运行速度快和占用内存小
二.时间复杂度
算法的效率可以使用时间复杂度和空间复杂度来分别衡量算法的运行速度和占用内存,在通常使用中,我们会优先保证时间复杂度更小。
1.原始的衡量方法:事后统计。多次运行测试好的程序,计算每次程序运行时间并求出平均一次程序的运行时间。显然这种方法有很多不合适的地方,如对于运行时间太长或会陷入死循环的程序无法统计、编辑好的程序在测试后发现不合适又舍弃影响效率、受到运行计算机性能的影响等
2.事前估算:在运行前使用统计学方法估算运行的时间成本。程序的运行时间受到算法、编译的代码质量、问题的规模、计算机性能等影响,显然我们更加关注算法的好坏,但是估算程序的运行时间需要考虑一些除算法外的因素,所以它并不能很好地衡量算法地好坏,我们应该只关注算法本身。我们可以采用算法的执行次数来衡量算法的好坏,这样就只考虑了算法本身,但是算法的执行次数也受到问题规模的影响,所以如果我们如果将问题规模记为n的话,我们可以使用一个代数式(记为f(n))来描述算法的执行次数。实际上我们还可以进一步简化一下,我们知道理论上问题规模n趋向于无穷大时,f(n)的结果也一定趋向于无穷大,因此我们可以只考虑趋向于无穷大时的等级即可,可以理解为随着问题规模变大,f(n)的结果增大的快慢。f(n)常见和常数C同级(C一般取1)、和n同级、和n2同级、和n*log n 同级等等。我们可以通过求f(n)和哪个常见等级代数式等价无穷大的方式得到算法的运算规模,也可以采用忽略次要因素的方式求得这个运算规模(求极限的方法),这个运算规模就作为算法的时间复杂度。
3.大O阶
记T(n)=O(f(n)),其中f(n)是算法的时间复杂度,T(n)是规模n的问题使用算法计算的执行次数,这种使用O(时间复杂度)的记录方法称为大O记法。从代码中抽象出T(n)的一些方法如下:
1)所有不在循环中的代码每一行都记为1
2)循环次数和运算规模无关的循环记为循环次数
3)循环次数和运算规模有关的循环中,将运算规模记为n再去表示循环的次数
4)如果是嵌套循环,也同样用n去表示循环次数(一般需要作数列求和)
4.一些代码的时间复杂度求解举例
1)
总共8行代码,没有循环,8和1是同阶无穷大,所以O(1),O(1)也称为常数阶
2)
代码中有一个for循环,循环次数和n有关,记为n次,总次数为n+1,n+1和n是同阶无穷大,所以O(n),O(n)也称为线性阶
3)
代码中有嵌套循环,外层循环次数n,内层循环次数n,总次数n2+1,因此O(n2),O(n2)也称为平方阶
4)
代码中有一个while循环,i每次翻倍,直到小于n,因此执行次数为log2n(向下取整),这个复杂度我们记为O(logn),O(logn)也称为对数阶
5.常见的时间复杂度大小排序
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
一般地,O(n3)之后的算法时间复杂度都应该避免出现,因为这样的算法能运算的问题规模非常小。
6.最坏情况和平均情况
对于一个规模为n的问题使用算法运算时,比如排列一列无序数字,可能给定的数字就是排列好的,这种情况直接就能得到结果,这是最好的情况;可能给定的数字完全和需要的排列方式相反(如需要按照从小到大排列,但是给定的数据恰好是从大到小排列好的),那么这种情况实际的运算步骤最多,这就是最坏的情况。显然我们可以根据最好情况得到一个时间复杂度,也可以根据最坏情况得到一个时间复杂度,还可以根据实际的算法得到一个统计学上的时间复杂度的期望值(称为平均情况),在实际选择算法时,我们一般根据实际需求和平均情况、最坏情况进行取舍。
以上是关于数据结构和算法学习笔记一:绪论和基本概念的主要内容,如果未能解决你的问题,请参考以下文章