算法相关概念

1.时间复杂度
时间复杂度被用于度量一个算法执行时间的长短。常见的算法时间复杂度有:常数阶O(1)、对数阶O(logn)、线性阶O(n)、线性对数阶O(n·logn)、平方阶O(n2)、立方阶O(n3)……k次方阶O(nk)和指数阶O(2n)等。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越来越低。也就是说时间复杂度从小到大依次为:O(1)

那么如何计算一个算法的时间复杂度?通常情况下,有以下几个简单的分析法则:1)对于简单的说明性语句、输入输出语句、赋值语句,可以近似认为其时间复杂度为O(1)。O(1)代表一个算法的运行时间为常数。2)对于顺序结构语句块,需要依次执行一系列语句,其时间复杂度遵循O记号下的“求和法则”。所谓“求和法则”指的是:如果算法的两个部分的时间复杂度分别为T1(n)=O(f(n))和T2(n)=O(g(n)),那么可以得到T1(n)+T2(n)=O(max(f(n),g(n))),特别地,如果T1(m)=O(f(m)),T2(n)=O(g(n)),那么T1(m)+T2(n)=O(f(m)+g(n))。

3)对于选择结构语句块(例如if语句),检验判定条件需要O(1)时间,此外,每一次该语句块只有其中一个分支会被执行,因此它的运行时间是检验判定条件的时间加上执行一个分支语句所用的时间。4)对于循环结构语句块,循环语句的运行时间主要体现在多次执行循环体以及检验循环条件的时间耗费,其时间复杂度遵循O记号下的“乘法法则”。所谓乘法法则指算法的两个部分时间复杂度分别为T1(n)=O(f(n))和T2(n)=O(g(n)),那么,T1*T2=O(f(n)g(n))。我们可以将循环体被执行的次数设为T1(n),将执行一次循环体内语句所需时间看作T2(n),那么该循环语句块的执行时间为T1T2。

以上几点规则只是针对一些简单算法或是逻辑结构简单的情况,当算法中采用了复杂的结构或者各种结构嵌套时,单纯使用上述方法显然很难正确地求解算法的时间复杂度,针对这些复杂的情况,最好的方法就是先将它分为几个容易估算的部分,然后再利用求和法则和乘法法则技术计算整个算法的时间复杂度。

2.空间复杂度读到这里,很多读者可能会有这样一个问题,为什么在衡量算法效率的时候,更多的是关注算法的时间复杂度,而不是算法的空间复杂度,难道空间复杂度就不重要吗?如果不重要,为什么很多时候又特别强调在O(n)或是其他数量级的空间复杂度内解决指定的问题呢?

其实,算法的空间复杂度并非不重要,也并非技术人员不去关注它,只是相较于时间复杂度,技术人员更多地会关注算法的时间性能。空间复杂度的分析方法与时间复杂度的分析方法类似,一个算法的空间复杂度也通常都与该算法的输入规模n有关系,通常也被表示为一个关于n的函数。定义S(n)是一个算法的空间复杂度,通常可以表示为S(n)=O(f(n))或S(n)=Θ(f(n)),其中,n为输入的规模,f(n)表示算法所需的存储空间。

一个程序在执行时,除了需要存储空间来存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的存储单元以及一些为得到计算所需信息的辅助空间。具体而言,程序执行时所需存储空间主要包括以下两部分:固定部分与可变部分。固定部分空间的大小与输入/输出的数据的个数多少、数值无关,主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等。这部分属于静态空间。可变部分主要包括动态分配的空间以及递归栈所需的空间。这部分的空间大小与问题规模有关。举一个例子,如果一个算法的空间复杂度为O(1),那么说明数据规模n和算法所需的辅助空间大小无关,即算法的空间复杂度为一个常量,不随被处理数据量n的大小而改变,并不是说该算法仅仅使用一个辅助空间。当一个算法的空间复杂度与被处理数据量n呈线性比例关系时,可表示为O(n)。

分析一个算法所占用的存储空间要从各方面综合考虑。例如,对于一个算法而言,如果用递归方式实现,那么代码量一般比较简短,几行代码即可实现,但是需要注意的是,虽然算法本身所占用的存储空间较少,然而由于在执行过程中需要多次进行函数调用(调用函数自身),所以在运行时需要一个附加堆栈来记录函数调用的有关信息,从而会产生额外较多的临时存储单元;如果采用非递归的方法实现该算法,那么程序的逻辑关系将会变得较为复杂,代码量也随之增加,导致代码本身占用的存储空间较递归实现方式多一些,但由于函数调用次数较少,便使得运行时只需要较少的辅助存储单元。此外,若算法的形参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若算法的参数传递方式为引用,则也只需要为其分配存储一个地址的空间,用它来存储对应实参变量的地址,以便由系统自动引用实参变量。

其实,对于一个算法而言,其时间复杂度与空间复杂度往往不是孤立存在的,二者会相互影响,有时候,为了获得较好的时间复杂度,可能会使空间复杂度变高,即通常说的以空间换时间;然而,在位图法与Hash法等算法中,有时候又会为了获得较低的空间复杂度,而使时间复杂度变高。所以,在设计算法(特别是大型算法)时,只有综合考虑各种因素,例如算法的使用频率、数据量的大小、运行环境、系统要求等各方面因素,权衡利弊,才能够设计出符合需求的高效算法。

你可能感兴趣的:(算法,数据结构)