【入门必看-算法基础知识讲解】小白都也能看得懂_算法学习(1)

一、何为真正的算法:

上一节中提到:算法就是解决某个或者某类问题的办法,但是,这只是对算法的一个笼统的描述。一个真正的算法,包含以下5大特性:输入、输出、有穷性、确定性、可行性。

  • 输入输出: 算法具有零个或者多个输入,至少一个或者多个输出。输入可以为零,但是必须存在输出,输出的形式可有为确定的返回值或者日志的的打印等,如果没有输出,那算法的意思在哪里呢?
  • 有穷性: 指算法在执行有限的步骤后可以自动结束,不会出现无限的循环,且每个步骤在可以接受的时间完成。注意:这里的有穷性并不是单纯数学上的概念,它指的是一个可以接收的“边界”,如存在某种算法运行几年后可以得出结果,理论上也是符合有穷性。
  • 确定性: 算法的每一个步骤都是具有确定的意义,不会出现歧义,相同的输入必须得到相同的输出。
  • 可行性: 算法中每一步都可以转换成程序在计算机上运行,它意味着算法中的设计是可行的,但是并不意味着一定得到正确的结果。

二、好算法有哪些评判标准:

上一节我们介绍了一个算法具有的哪些特征,但是算法也分好坏,好的算法效率高,就好比“移山”,如果在古代可能只能用人力去挖,现代的话可以使用各种炸药、自动化设备去处理,不仅效率更高,安全性也更好,那么,衡量一个算法好坏有哪些标准呢?下面具体来看看吧!

2.1、正确性:

正确性:要求算法应该有输入、输出和执行无歧义,能够正确反映问题的具体需求,通过算法能够得到解决问题的正确答案。

2.1.1、“正确性”算法的四个层次

(1)算法程序没有语法错误

(2)算法程序对合法的输入能够得到满足要求的输出

(3)算法程序对非法的输入能够得到满足规格的输出

(4)算法程序对故意刁难的测试数据能够得到满足要求的输出

对于算法的第4层次,基本不可能实现将所有的输入逐一验证,所以算法的正确性一般只要满足到第3层次即可。

2.2、可读性:

一个好的算法设计,应该是方便大家阅读、理解和交流的,如果为了追求某些方面的特性,导致算法不易于人们理解,那这样的算法不能称为好的算法,因为人们无法轻易读懂它,导致难以修改和调试,即使算法中存在问题也不能轻易发现,最后可能算法的设计者在时间久远后也很难理解它。

2.3、健壮性:

好的算法应该对不合理的输入做到适当的处理(提示等),而不是产生让使用者也无法理解的异常或者莫名其妙的结果。

健壮性定义: 算法的输入数据不合法时,算法能够做出相应的适当处理,而不是产生难以理解的异常或者莫名其妙的结果。

2.4、时间效率高和存储量低:

算法也是来源生活,生活中我们都希望花最少的钱办最多的事,算法也是一样,能够占用最小的空间,最快的得到结果那就是一个好的算法。

时间效率高: 指的是通过算法设计的程序执行的时间短,一个问题存在着多种算法可以解决,使用时间最短的那个时间效率最高。

存储量低: 存储量是指实现算法的存储在运行时占用最大的存储空间,程序运行占用的空间越小,证明运行程序需求的资源越小,算法就越好(存储空间一般是指:内存或者硬盘等设备的存储空间)。

🟡 3.4、算法和程序的区别

有些小伙伴可能会将算法和程序两者的概念混淆,其实它们两者是不同的概念。算法表示的是解决某个或某类问题的思路、想法。程序是根据某一个特定算法编写出来可以被计算机运行的代码。

就比如我需要输出1到100范围内的所有数值,我们会考虑到使用循环语句输出,使用循环语句输出这个思路就可以说是算法,然后实际上根据这个思路编写出来的代码就可以称为程序。

四、算法效率的度量方法

📘 四、算法效率的度量方法

通过上文的介绍,大家已经对算法有了初步的了解,但是,实际情况如何衡量一个算法的好坏呢,相信现在大家心里都还是存在着这个疑惑的,下面就来看看有哪些度量方法吧!

🔶 4.1、事后统计方法

定义:不同的算法设计出不同的测试程序进行测试,然后统计计算机计时器在不同测试程序运行的时间进行比较,从而确定算法效率的高低。

1.1、事后统计方法存在的问题

1、某个问题或某类问题可以存在多种算法解决,如果每种算法都编写测试程序需要花费大量的时间和精力。

2、运行效率依赖于计算硬件和软件等环境因素,不同的硬件和软件有可能会掩盖了算法存在的问题,导致测试出来的结果不准确。

3、测试数据设计准备困难,程序的运行效率往往和测试数据的规模有关,如果测试数据太小,以现在CPU的运算速度,根本看不出差异,选择多大的测试数据规模,测试多少次才能够得到比较准确的结果等,这些问题都是很难进行判断的。

1.2、事后统计方法结论

基于事后统计方式存在的缺陷,这种算法效率的度量方式是不推荐使用的。

🔷 4.2、事前统计方法

定义:在进行算法程序编写前,依据统计方法对算法进行估算,得到算法程序运行的预估值。 计算机的前辈们经过分析发现,通过高级程序语言编写的程序在计算机运行时消耗的时间取决于下面的几个因素:

在这里插入图片描述

通过上面的图片可以发现,因素2取决于软件的支持,因素4取决于运行程序的硬件,抛开软件、硬件有关的因素,一个程序的运行效率,依赖于算法的好坏和问题的输入规模(即输入量的多少)。

下面我们通过求和的两种算法来实际分析与程序的运行时间相关的具体因素:

算法一:累加求和

int i,sum=0,n=100; // 执行1次
for(i=1;i<n;i++){
	sum = sum + i; // 执行n次
}
System.out.println("sum="+sum); // 执行1次

算法二:高斯算法

int i,sum=0,n=100; // 执行1次
sum = (1 + n) \* n / 2; // 执行1次
System.out.println("sum="+sum); // 执行1次

通过上面求和的两个算法我们会发现,如果将头尾变量定义和循环判断等开销忽略,实际上两种算法就是运行n次和1次的区别,随着n的数值越大,它们之间运行的次数差距也越大,程序花费的时间差距也越大,因此,我们可以得出一下的一个结论:

测定运行时间最可靠的方法,就是计算对运行时间有消耗的基本操作的执行次数,运行时间和这个计数成正比。

结论:

对于输入规模为n,第一种求和算法中,求和操作 sum = sum+ i 代码需要被运行n次,我们可以说这个问题的输入规模n使得程序的操作数量是:f(n) = n

对于输入规模为n,第二种算法中求和代码:sum = (1 + n) * n / 2 始终只需要执行一次,那么我们可以说这个问题的输入规模为n使得程序的执行数量是:f(n) = 1

因此,在进行分析一个算法的运行时间时,我们需要将输入规模和程序的基本操作数量进行关联起来即将基本操作数量表示成输入规模的函数,如下图所示:

在这里插入图片描述

五、时间复杂度和空间复杂度

📙 五、时间复杂度和空间复杂度

🟧 5.1、时间复杂度

在数据结构中,使用时间复杂度来衡量程序运行时间的多少。每条语句执行的次数称为该语句的频度,整段代码的总执行次数则称为整段代码的频度。

定义:在算法估算时,语句的执行次数T(n)是关于问题规模n的函数,从而分析T(n)随着n的变化的关系。算法的时间复杂度也称为算法的时间量度,记作T(n) = O(f(n)),它表示随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度,其中f(n)是问题规模n的某个函数。

刚开始看上面的定义多少有些迷惑,但是多读几次结合上文的知识串起来后,你会其实并没有这么复杂,时间复杂度其实可以理解为随着问题规模n的增大,程序语句执行频度的增长率。

在定义中我们使用到O()的方式来体现算法时间复杂度的记法,这种方式又称为大O记法。一般情况下,随着问题规模n的增大,T(n)即语句执行次数增长最慢的算法为最优算法,讲简单点,就是无论你输入规模如何变化,只要执行的语句次数增长最小,那这种算法就是最优的。

了解算法时间复杂度的定义,那么如何分析一个算法的时间复杂度呢(即如何推到大O阶呢)?没错,经过前辈们的经验,这个也是有相应的推导公式的,在推导的时候我们应该采用无限大的思想来简化大O表达式,具体如下:

  • 用常数1代替运行时间中的所有加法的常数,如:某个算法的执行函数为f(n) = 10,则替换成大O阶方法的话则为:O(1),无论这个常数为10,还是100,还是1000都使用1替换,因为执行函数和问题规模n的大小无关,它是执行时间恒定的,像时间复杂度为O(1)的又被称作常数阶。
  • 如果表达式有多项含有无限大变量的式子,只保留一个拥有指数最高的变量的式子。例如 2n²+2n 简化为 2n²;
  • 如果最高阶项存在且系数不为1,则去除掉与这个项相乘的系数,例如 2n² 系数为 2,直接简化为 n² ;

经过上面三个步骤推到出来的结果就是算法对应的大O阶。

对算法的时间量度,存在两种方式。 一种是计算所有情况的平均值,这种时间复杂度的计算方法称为平均时间复杂度。另一种情况则为计算最坏情况下的时间复杂度,这种也称为最坏时间复杂度,一般没有特殊说明的情况下,指的都是最坏时间复杂度。

🟨 5.2、常见的时间复杂度例子

一、常数阶

int i,sum=0,n=100; // 执行1次
sum = (1 + n) \* n / 2; // 执行1次
System.out.println("sum="+sum); // 执行1次

这个算法就是上面我们举例到的高斯算法,程序的执行次数函数为f(n) = 3,根据大O阶方法的推导方式,则得到的时间复杂度为:O(1),而不是O(3),注意:因为执行函数并不会随着n的变化而变化,它是恒定的,像复杂度为O(1),又被称作常数阶。

二、线性阶

int i,sum=0,n=100; // 执行1次
for(i=1;i<n;i++){
	sum = sum + i; // 执行n次
}
System.out.println("sum="+sum); // 执行1次

根据上面的代码,我们可以发现执行次数函数为f(n) = n,根据大O阶方法的推导方式得到它的时间复杂度表示为:O(n)。 像这种线性阶,我们主要分析的是循环结构中的一个运行情况,从而得到它的时间复杂度。

三、对数阶

int condition = 1;
while(condition < n){
	condition = condition \* 2;
}

根据上面的代码,我们会发现循环语句的条件会在每次condition乘以2后更加接近跳出条件,既满足多少个与2的乘积后将会退出循环,因此我们可以得到执行次数的函数为:f(n) => 2x = n ===> x = log2n,根据大O阶方法的推导方式得到它的时间复杂度表示O(logn)。

四、平方阶

for(int i=o;i<n;i++){
	for(int j=o;j<n;i++){
		...
	}
}

根据代码分析,我们可以得到执行次数的函数为: f(n) = n2,根据大O阶方法的推导方式得到它的时间复杂度表示O(n2)。

五、常见的时间复杂度耗费时间比较

O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n ) < O(n!) < O(nn)

常见的时间复杂度耗费时间比较

🟦 5.3、空间复杂度

在数据结构中,用空间复杂度来衡量程序运行所需内存空间的大小,跟时间复杂度类似,它也可以使用大O记法来表示。

算法的空间复杂度是通过计算算法所需的存储空间实现的,计算公式为:S(n) = O(f(n)),其中n为问题的规模,f(n)则为语句关于问题规模n所占存储空间的函数,随着n的变动,f(n)的增长率越小越好。

一个算法程序从编译到运行有多个部分涉及存储空间的分配,具体情况如下:

  • 程序代码本身需要占用一部分存储空间,用于存储编译后提供执行的代码,这部分的存储空间主要取决于程序的代码量,因此,为了减少这部分占用的空间,在保证算法的合理性情况下,应该尽量减少代码量。
  • 程序中的输入输出,也需要占用一部分存储空间,这部分的占用的空间主要取决于不同算法的实现逻辑,但是大体上它们的大小都是相差不大的。
  • 程序在运行时,不同情况下需要申请的临时空间,这部分占用的空间是对空间复杂度影响最大的,因为不同的算法实现细节可能存在较大的差异,会申请的空间也会存在比较大的不同。

做了那么多年开发,自学了很多门编程语言,我很明白学习资源对于学一门新语言的重要性,这些年也收藏了不少的Python干货,对我来说这些东西确实已经用不到了,但对于准备自学Python的人来说,或许它就是一个宝藏,可以给你省去很多的时间和精力。

别在网上瞎学了,我最近也做了一些资源的更新,只要你是我的粉丝,这期福利你都可拿走。

我先来介绍一下这些东西怎么用,文末抱走。


(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

(4)200多本电子书

这些年我也收藏了很多电子书,大概200多本,有时候带实体书不方便的话,我就会去打开电子书看看,书籍可不一定比视频教程差,尤其是权威的技术书籍。

基本上主流的和经典的都有,这里我就不放图了,版权问题,个人看看是没有问题的。

(5)Python知识点汇总

知识点汇总有点像学习路线,但与学习路线不同的点就在于,知识点汇总更为细致,里面包含了对具体知识点的简单说明,而我们的学习路线则更为抽象和简单,只是为了方便大家只是某个领域你应该学习哪些技术栈。

在这里插入图片描述

(6)其他资料

还有其他的一些东西,比如说我自己出的Python入门图文类教程,没有电脑的时候用手机也可以学习知识,学会了理论之后再去敲代码实践验证,还有Python中文版的库资料、MySQL和HTML标签大全等等,这些都是可以送给粉丝们的东西。

在这里插入图片描述

这些都不是什么非常值钱的东西,但对于没有资源或者资源不是很好的学习者来说确实很不错,你要是用得到的话都可以直接抱走,关注过我的人都知道,这些都是可以拿到的。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值