算法分析基本概念

      一个算法的要求有四个:有输入、有输出、有限性、确定性。

       有一个很著名的公式是程序=数据结构+算法。由该式子能看出算法和程序的关系,算法是一段有限序列能够解决一个问题,是解决问题的方法。程序是一个实在的东西,能够解决一个问题。算法和程序相比,算法强调的是方法,所以算法不拘泥于各种编程语言,没有严格的语法要求,在本课程中算法使用伪代码来表示(伪代码的使用格式在本文文末)。

      衡量算法好坏的两个标准是算法使用的时间和占用的空间,但随着科技不断进步,硬件设备的存储空间不断增大,空间比重相对较小。但在一些嵌入式设备中占用的空间却是第一要考虑的因素,但本课程中只是考虑使用的时间,所以对于空间不加赘述。

      在算法中使用时间的主要是基本操作,并且在本课程中基本操作主要包括两种:比较操作和赋值操作。以比较和赋值的次数多少作为衡量算法好坏的标准。其中在大量复杂算法中包含两类简单算法:查找和排序。这两种算法在上学期的数据结构课程中都已经学习过部分,但当时并未强调所用时间。查找排序数据主要的存储方式是数组,在这两类算法中数据排列的方式对于算法的好坏起着一定的决定作用,下面就以几个具体的例子来进行说明。

1. 二分搜索

      二分搜索也叫折半查找,是要求数据有序的前提下,每次减少一半的查找数量。

      数据的比较次数范围是:1~log(n)向下取整加一

2. 合并有序表:

      合并有序表是指定两个标记,将标记中较小或较大的数字存在临时的辅助空间中,达到最终排序的目的。假设两段数据长度分别为n1 和n2,并且n1是较小的部分.
       数据的比较次数是:n1~n1+n2-1
       n1是当前一段数据的最大值小于后一段数据的最小值的情况。例如:n1(1,2,3),n2(4,5,6,7)。n1+n2-1是当两段数据中的元素交叉大小的时候。例如:n1(1,3,5,7),n2(2,4,6,8)。
      数据的赋值次数是:2(n1+n2)

3. 选择排序

      选择排序是从第一位开始,选择后面数据中最小的那个数据,与当前的数据进行位置交换。
      数据的比较次数是:n-1~n(n-1)/2
      n-1是数据已经是想要的顺序,每一步比较一次即可.n(n-1)/2是当数据逆序有序时后的情况,这种情况下每两个数据都要比较一次.
      数据的赋值次数是:0~3(n-1)
      赋值次数的最好最坏情况分别对应于比价的最好最坏情况,已经有序无须做任何交换,逆序需要交换(n-1)次,并且每两个数据交换就要进行三次赋值操作

4. 插入排序:

      插入排序是从第二个起,寻找该元素在前面元素中正确的位置,并将该元素插入进去。同时每次比较要将被比较元素向后移位

      数据的比较次数是:n-1~n(n-1)/2
      n-1是数据已经有序,每次直接向后移位。(n-1)n/2是逆序有序,每个元素都要与之前的所有元素进行比较。

      数据的赋值次数:数据的比较次数加上n-1
      数据的赋值包括比较元素的最终赋值以及过程中被比较元素依次向后移位,总体上看,比较次数在加n-1即为赋值次数

5. 向上合并排序:

       将相邻的2的i次方个元素每次合并为一段元素,并对这段元素使用归并排序使之有序。最后使整体有序。
      数据比较次数:n*log(n)/2~nlog(n)-n+1
      最好情况对应于merge过程中的最好情况,即第一个序列的最大值小于第二个序列的最小值,最坏情况对应于merge过程中两序列交叉的最坏情况。总体来说比较分为logn层
      赋值次数:2n
logn次

      前文指出,衡量算法的依据就是算法运行的时间,专业名词叫“时间复杂度”。求解时间复杂度是一项困难的工作,因为在算法中随着输入序列的变化分为最好情况和最坏情况。所以没有确切的公式去计算具体的值。于是采用渐近线的思想,类似于一种贴近,把时间复杂度用框架框起来。使用如下符号作为框架中的各个标准:

1) 大O符号

在这里插入图片描述
      大O符号意思就是时间复杂度的上界,类似于最坏情况,该算法的时间复杂度永远小于大O,举例:㏒n = O(n)

2) 大ω符号

在这里插入图片描述
      大ω符号意思是时间复杂度的下界,类似于最好情况,该算法的时间复杂度永远大于大ω,举例n = ω(㏒n)

3) θ符号

      若一个算法的大O符号,大ω符号中的函数是同一个函数,则用θ来表示,同时可以用θ来表示时间复杂度。

      对于大O符号和大ω符号,常表示之间的阶数相差不大。上界和下界的表示是相对的,也可用小写来进行表示,小写一般代表阶数相对较大,距离㏒n = o(n2), n㏒n = 小ω(㏒n)

      对于空间复杂度研究的不多,但需要牢记,计算空间复杂度的时候不算输入数据所占有的空间,只计算算法过程中,使用的临时变量或者辅助数组所占的空间。

最优算法:

      最优算法不是指某一个算法,而是某一类算法。判断的方式就是使用时间复杂度的方法,若算法的下界为A(n),若证明上界也为A(n)的函数,则可以说明该算法是最优算法。
在这里插入图片描述
      以上的过程在本书中,出现的题目多为证明题。证明一个算法小于某个上界或者小于某个下界或上界下界相等。一定要牢记三种标准的定义,来进行证明。

估算算法的运行时间:

      这是一类计算题,分三大种主要的方法。都是寻找比较核心的操作,计算操作的运行次数作为判断时间复杂度的标准。该类题的计算方法大多列出连加式,再通过数学方法进行计算。

      1)计算迭代次数:寻找到各阶循环中的基本操作,以他循环的次数作为最终的结果。

      2) 计算基本运算的频度:前文提出了迭代的次数与输入数据的顺序有关系,当迭代次数不稳定的时候,可以选择计算基本运算的频度来作为衡量时间的标准。以Merge算法为例,当不了解输入数组A和输入数组B之间的关系时,可以选择以赋值操作的频度作为标准。为2n。

      3) 使用递推关系:在某一类基本操作确定后,发现基本操作含有递归地定义,那么使用数学方法,找到f(n)和n之间的关系

最坏情况分析和平均情况分析:

       在时间复杂度的分析中,分析最好情况是没有太多意义的,因为最好的情况不是总发生,不具有代表性。而最坏情况是算法的上界,可以通过分析最坏情况确定最后的界限,并在此之前采取相应的措施。但有的时候最坏情况不是足够客观,使用平均情况可以有效的减少最后的结果,但平均情况有特殊的要求:必须了解到各个运算在算法中输入的各种概率,所以平均情况分析相对复杂。

平摊分析:

      因为最坏情况分析比较好计算,在大多数情况下使用最坏情况,但如果最坏情况占输入的比例非常小的时候,全按照最坏情况分析所得出的时间复杂度将会高出一个阶,于是为了平衡之间的关系,给出更合理的时间复杂度,会使用平摊分析的方法。平摊分析的具体情况可见博客:link

      以上是第一章的主要内容,在开头首先介绍的是算法分析的方法。在后面的章节中会介绍具体的算法,作为基础应掌握牢固。

伪代码的使用规范:

  1. 要有文字说明的输入和输出

  2. 每行语句前要有数字表示行数,输入输出除外

  3. 赋值统一用箭头表示

  4. 对于while要用end while(单列一行),for要用end for(单列一行)来进行表示

  5. 在进行if操作是,在then后面写if内的操作

猜你喜欢

转载自blog.csdn.net/gls_nuaa/article/details/104896513