Day-2 演算法介绍

演算法(Algorithms)

大致上来说,演算法为具有明确定义的计算过程,根据输入得到不同的输出,演算法就是一个将输入变成输出的一连串的计算过程,且须要具备五个特性。
输入 + 演算法 = 输出

来源:http://ms2.ctjh.ntpc.edu.tw/~luti/107-2/images/01.jpeg

  1. 输入(input):演算法会有零或一个输出。
  2. 输出(output):演算法会有一个或多个输出。
  3. 有限性(finiteness):演算法应在有限的步骤内完成。
  4. 明确性(definiteness):演算法的每一个步骤应明确而不含糊的。
  5. 有效性(effectiveness):演算法的每一个步骤应可被执行且有效。

一个演算法虽然我们非常注重他的效能,但也有一些比效能更为重要的议题需要注意

  • 正确性(Correctness)
  • 简洁性(Simplicity)
  • 可维护性(Maintainability)
  • 稳定性(Stability)
  • 模组化(Modularity) : 让我们只要修改局部程序码,就能改变其功能
  • 安全性(security) :
  • 可扩充性(Scalability)

举例,Java虽然比C效率慢了许多,但由於提供物件导向和异常检查等功能,我们愿意牺牲一些效能换取到这些东西。

我们也可以将演算法是为解决特定问题的工具,例如我们要将一连串的没有顺序的数字进行排序,由小排到大,这是一个非常常见的问题,我们可以试着正式定义一下这个问题。

演算法问题定义

Input: 一连串正整数,从https://chart.googleapis.com/chart?cht=tx&chl=a_1https://chart.googleapis.com/chart?cht=tx&chl=a_n 所构成的集合{https://chart.googleapis.com/chart?cht=tx&chl=%20%7B%20a_1%2Ca_2%2C...%2Ca_n%7D}
Output: 一连串重新排列的正整数 {https://chart.googleapis.com/chart?cht=tx&chl=%7B%20a_1'%2Ca_2'%2C....%2Ca_n'%20%7D},且 https://chart.googleapis.com/chart?cht=tx&chl=a_1'%20%3C%3D%20a_2'%20%3C%3D%20...%20%3C%3D%20a_n'

举例来说,给定一连串正整数集合 {https://chart.googleapis.com/chart?cht=tx&chl=%7B%2031%2C41%2C59%2C26%2C41%2C58%20%7D},经过排序演算法会得到输出
{ https://chart.googleapis.com/chart?cht=tx&chl=26%2C31%2C41%2C41%2C58%2C59 }。对於这样的输入,我们称为这个输入为排序问题的实例(instance),一般来说,一个问题的实例由输入所构成,且这些输入需要满足这个演算法的输入条件,以这个例子来说,输入的条件为正整数所构成的集合,我们给定的实例就必须皆为正整数。

要使用哪一种演算法,会取决於我们输入的多寡,或是根据电脑架构等因素,会影响到我们演算法的选择。

一个演算法要说他是正确的,必须要有以下条件 : 对於每一个输入的实例,都会输出如演算法预期的输出,且在输入完成时,该演算法就会随之停止。那这个演算法就可以称为能够解决某问题的正确演算法。对於一个不正确的演算法来说,会发生在输入完成後,演算法却没有停止,或是输出结果不符合预期。

要描述一个演算法,我们可以直接使用虚拟码进行描述,或是程序码,HDL等,唯一需要遵守的原则就是必须精确的描述每一个计算步骤的行为。

资料结构

资料结构是一种储存资料的方式,将这些资料以特定的方式进行阻止以方便我们进行修改和存取。当然,没有一种资料结构可以有效率的达成我们所有的目的,因此了解每一种资料结构的优势和劣势是十分重要的。

演算法效率(Algorithms Efficiency)

一个问题我们设计了不同的演算法是因为在不同的输入,硬体或是软件条件之下,会有不同的效率。

举例来说,针对排序,我们知道有插入排序演算法(insertion sort),在排列n个物件的情况所需花费的时间大约为https://chart.googleapis.com/chart?cht=tx&chl=c_1n%5E2https://chart.googleapis.com/chart?cht=tx&chl=c_1为常数,且不受到n的影响。也就是说,这个演算法所需花费的时间大约和https://chart.googleapis.com/chart?cht=tx&chl=n%5E2呈线性关系。

第二种为合并排序法(merge sort),所需花费的时间大约为https://chart.googleapis.com/chart?cht=tx&chl=c_2nlg_nhttps://chart.googleapis.com/chart?cht=tx&chl=c_2为常数,且不受到n的影响。(https://chart.googleapis.com/chart?cht=tx&chl=lg的意思为https://chart.googleapis.com/chart?cht=tx&chl=log_2)

我们假设插入排序法需要的时间为https://chart.googleapis.com/chart?cht=tx&chl=c_1n%5E2,合并排序法要花费的时间为https://chart.googleapis.com/chart?cht=tx&chl=c_2nlg_n,我们试着分析这两种演算法所需要花费的时间。

一般来说,插入排序法的常数https://chart.googleapis.com/chart?cht=tx&chl=c_1,会小於合并排序法的https://chart.googleapis.com/chart?cht=tx&chl=c_2。插入排序法所需要的时间受到n所影响,合并排序法受到https://chart.googleapis.com/chart?cht=tx&chl=log_n所影响,我们可以试着比较,如果https://chart.googleapis.com/chart?cht=tx&chl=n%20%3D%2010时,https://chart.googleapis.com/chart?cht=tx&chl=lg_n大约为3.2,https://chart.googleapis.com/chart?cht=tx&chl=n%20%3D%201000时,https://chart.googleapis.com/chart?cht=tx&chl=lg_n大约为10,当https://chart.googleapis.com/chart?cht=tx&chl=n%20%3D%201000000时,https://chart.googleapis.com/chart?cht=tx&chl=lg_n大约为20。我们可以看到在n足够大时,合并排序法所花费的时间相较於插入排序法要少的非常多,但在n较小时,反而插入排序法比合并排序法还要来的快,因为常数的关系,n够大时,补偿了常数所产生的差异。不论https://chart.googleapis.com/chart?cht=tx&chl=c_1https://chart.googleapis.com/chart?cht=tx&chl=c_2小多少,一定会在测资达到n笔时,合并排序法的速度大於插入排序法。

我们假设在一个环境下,有两部电脑,一台为A电脑,速度非常的快,执行插入排序法。另一台为B电脑,速度比A电脑还要慢,执行合并排序法。让这两部电脑去针对一个阵列进行排序,阵列中有一千万个元素,假定A电脑每一秒钟可以处理https://chart.googleapis.com/chart?cht=tx&chl=10%5E%7B10%7D 笔指令,B电脑每一秒钟可以处理https://chart.googleapis.com/chart?cht=tx&chl=10%5E7笔指令,所以,大致上我们可以说A电脑比B电脑快了1000倍。我们可以大致上计算一下A电脑和B电脑所需要花费的时间,如下图所示


由此可见,A电脑需要超过5.5个小时才能够完成排序的工作,而B电脑需要的时间只需要20分钟以内就能够完成排序的工作,可见一个好的演算法的重要性。

在资料量足够大时,电脑效能带来的影响大约就是一个常数因子而已,

对於θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E2)和θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E3),总会存在一点n使得θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E3)的增长率大於θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E2)

但这也不表示我们弃用一些低速的演算法,假设n要足够大时,才会导致θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E3)的增长率大於θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E2),而这个n大到电脑无法负荷,也就是电脑的效能根本达不到n这样的资料量处理,这时候我们就会考虑使用这些低速的演算法,我们可以看到在资料规模够小时,θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E2)是要比θhttps://chart.googleapis.com/chart?cht=tx&chl=(n%5E3)来的更加快速。

(p.s : 编辑器居然不支援LaTex...,还是我的问题XD 麻烦底下留言告知 感恩~)
参考资料: Introduction to algorithms 3rd


<<:  onnx - 用 netron 查看 onnx 模型版本参考笔记

>>:  基础建设: 系统监控与告警

Day 06:3 Sum

在Two Sum 中 我们一开始最初的想法是用2次的loop检查,那换做这3 Sum我们当然可以用三...

30天轻松学会unity自制游戏-制作PlayerHP

敌机会攻击後,考量游戏难易度,让玩家飞机能多扛几下子弹,先给玩家一个HP血条,等血量见底再说,在Hi...

[Day_26]函式与递回_(5)

函式的回传值 函式回传值可以使用tuple回传多个资料,例如:以下ymd函式使用tuple回传时间的...

Day7 资料储存 - object storage优缺点及场景

优缺点 优点 方便扩增: 由於Object storage是扁平化架构,只要增加机器就是增加这个大平...

Day-8 字串(下)

用 [] 来取得字元 要取出某个字元,可以指定他的offset,第一个为最左边的offset 是 0...