求分析一下这个遗传算法求函数最优解(函数)的复杂度QAQ

(乱野追踪.)
(飞翔的小鸟)
第三方登录:rel="nofollow"
target="_blank"
class="itm noul
" hidefocus="true" href="http://blog.163.c算法复杂度_百度百科
清除历史记录关闭
声明:百科词条人人可编辑,词条创建和修改均免费,绝不存在官方及代理商付费代编,请勿上当受骗。
算法复杂度
算法复杂度是指算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。应用于数学和计算机导论。
算法复杂度简介
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从和来考虑。
算法复杂度时间复杂度
(1)时间频度
一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。算法的是指执行算法所需要的计算工作量。
(2)时间复杂度
在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进,简称时间复杂度。
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1),另外,在时间频度不相同时,时间复杂度有可能相同,如T(n)=n^2+3n+4与T(n)=4n^2+2n+1它们的频度不同,但时间复杂度相同,都为O(n^2)。
按数量级递增排列,常见的时间复杂度有:
常数阶O(1),对数阶O(log2n)(以2为底n的对数,下同),线性阶O(n),
线性对数阶O(nlog2n),平方阶O(n^2),立方阶O(n^3),...,
k次方阶O(n^k),指数阶O(2^n)。随着问题规模n的不断增大,上述不断增大,算法的执行效率越低。
算法的时间性能分析
(1)算法耗费的时间和语句频度
一个算法所耗费的时间=算法中每条语句的执行时间之和
每条语句的执行时间=语句的执行次数(即频度(Frequency Count))×语句执行一次所需时间
算法转换为程序后,每条语句执行一次所需的时间取决于机器的指令性能、速度以及编译所产生的代码质量等难以确定的因素。
若要独立于机器的软、来分析算法的时间耗费,则设每条语句执行一次所需的时间均是单位时间,一个算法的时间耗费就是该算法中所有语句的频度之和。
求两个n阶方阵的乘积 C=A×B,其算法如下:
#&define&n&100&//&n&可根据需要定义,这里假定为100
void&MatrixMultiply(int&A[n][n],int&B&[n][n],int&C[n][n])
{&//右边列为各语句的频度
&&&&int&i&,j&,k;
&&&&for(i=0;&i&n;i++)&//n
&&&&for&(j=0;j&n;j++)&{&//n*n
&&&&&&&&C[i][j]=0;&//n?
&&&&&&&&for&(k=0;&k&n;&k++)&//n?*n
&&&&&&&&C[i][j]=C[i][j]+A[i][k]*B[k][j];//n?
该算法中所有语句的频度之和(即算法的时间耗费)为:
T(n)=2n3+3n2+2n (1.1)
语句(1)的循环控制变量i要增加到n,测试到i=n成立才会终止。故它的频度是n+1。但是它的循环体却只能执行n次。语句(2)作为语句(1)循环体内的语句应该执行n次,但语句(2)本身要执行n+1次,所以语句(2)的频度是n(n+1)。同理可得语句(3),(4)和(5)的频度分别是n2,n2(n+1)和n3。
算法MatrixMultiply的时间耗费T(n)是矩阵阶数n的函数。
(2)问题规模和算法的
算法求解问题的输入量称为问题的规模(Size),一般用一个整数表示。
矩阵乘积问题的规模是矩阵的阶数。
一个图论问题的规模则是图中的顶点数或边数。
一个算法的时间复杂度(Time Complexity, 也称)T(n)是该算法的时间耗费,是该算法所求解问题规模n的函数。当问题的规模n趋向无穷大时,时间复杂度T(n)的数量级(阶)称为算法的渐进时间复杂度。
算法MatrixMultiply的T(n)如(1.1)式所示,当n趋向无穷大时,显然有T(n)~O(n^3);
这表明,当n充分大时,T(n)和n^3之比是一个不等于零的常数。即T(n)和n^3是同阶的,或者说T(n)和n^3的数量级相同。记作T(n)=O(n^3)是算法MatrixMultiply的渐近时间复杂度。
(3)渐进时间复杂度评价算法时间性能
主要用算法时间复杂度的数量级(即算法的渐近时间复杂度)评价一个算法的时间性能。
算法MatrixMultiply的时间复杂度一般为T(n)=O(n^3),f(n)=n^3是该算法中语句(5)的频度。下面再举例说明如何求算法的。
交换i和j的内容。
以上三条单个语句的频度均为1,该的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为常数阶,记作T(n)=O(1)。
注意:如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。
变量计数之一:
(1) x=0;y=0;
(2) for(k-1;k&=n;k++)
(4) for(i=1;i&=n;i++)
(5) for(j=1;j&=n;j++)
一般情况下,对步进只需考虑循环体中语句的执行次数,忽略该语句中步长加1、终值判别、控制转移等成分。因此,以上程序段中频度最大的语句是(6),其频度为f(n)=n^2,所以该程序段的为T(n)=O(n^2)。
当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。
变量计数之二:
(2) for(i=1;i&=n;i++)
(3) for(j=1;j&=i;j++)
(4) for(k=1;k&=j;k++)
该中频度最大的语句是(5),内循环的执行次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,而最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执行次数:
则该程序段的时间复杂度为T(n)=O(n^3/6+低次项)=O(n^3)。
(4)算法的不仅仅依赖于问题的规模,还与输入实例的初始状态有关。
在数值A[0..n-1]中查找给定值K的算法大致如下:
(2)while(i&=0&&(A[i]!=k))
此算法中的语句(3)的频度不仅与问题规模n有关,还与输入实例中A的各元素取值及K的取值有关:
①若A中没有与K相等的元素,则语句(3)的频度f(n)=n;
②若A的最后一个元素等于K,则语句(3)的频度f(n)是常数0。
算法复杂度空间复杂度
与类似,是指算法在计算机内执行时所需存储空间的度量。记作:
S(n)=O(f(n))
算法执行期间所需要的存储空间包括3个:
·算法程序所占的空间;
·输入的初始数据所占的存储空间;
·算法执行过程中所需要的额外空间。
在许多实际问题中,为了减少算法所占的存储空间,通常采用压缩存储技术。
算法复杂度复杂度分析
通常一个算法的复杂度是由其输入量决定的,随着输入的增加,
不同算法的复杂度增长速度如右图所示:
为了降低算法复杂度,应当同时考虑到输入量,设计较好的算法。
清除历史记录关闭浅谈分治算法的时间复杂度分析
在我的周围, 发现好多的同事, 朋友, 对一个算法进行时间复杂度分析时,
尤其是递归函数进行分析时, 比较吃力, 因此特写这篇文章, 给刚做程序员或者对分治算法(Divide and Conquer),
递归(Recursive)算法时间复杂度不太会分析的同学吧. 如有不对之处,共同探讨学习。
关于分治算法是这样定义的:
为解决一个给定的问题, 算法需要一次或多次的递归调用其自身来解决相关的子问题.
即我们把一个大规模的问题划分为n个规模较小的而结构与原来相似的子问题,
递归解决这些子问题,然后再合并其结果。这样就得到了最终的结果。
从步骤上来讲, 可以分为三步:
1. 分解(Divide): 将一个问题为N的问题分解成一系列子问题。
2. 解决(Conquer): 递归的处理每个子问题.如果子问题足够小,
则直接给出解。
3. 合并(Combine): 把每个已经处理好的子目问题合并,
得到最终的解。
递归调用时, 最关键的就是递归调用栈的深度. 我们也可以理解为分治算法中,
被分成的段数。 也就是步骤中的第1步中所分成的子序列的个数。 假设这个递归调用深度我们用&D(n)
另外一个就是在每次处理一个具体子序列时,所用的时间复杂度,我们用C来表示。
则最终的这个函数的时间复杂度为:
(注:教科书上是:αT(n/b) + D(n) + C(n), 这个问题我们后面再讲)。
讲到这里, 肯定很多人都想到了快速排序算法, 这是一个典型的递归函数.
在这里用表示如下
QuickSort(int low, int * p)
得到分界点nPos
nPos = GetDividedPosition(low, high,
对分界点左边排序
QuickSort(low, nPos-1, p);
//&对分界点右边排序
QuickSort(nPos+1, high, p);
在这里,&获取分界点函数
GetDividePostion它的效率是n的,即给定一个数组,只需要一次遍历就可以得到结果,因此它是一个Ѳ(n)的效率。那D(n)是多少呢?
从函数中我们可以分析出,每次它都是把序列分成两部分,&在最优的情况下,即每次都分成两等份,那它的问题子序列个数就是
Log2N&个,那在最好情况下的时间复杂度就可以理解为
Ѳ(NLog2N)
我们可以讨论一个它的最差情况是什么样的。在最差情况下,待排序序列是从大到小的,而要排成从小到大的,如果按照每次取基准点为数组的第一个值的话,每次得到的nPos为序列的第一个值,快速排序中形成的子序列第一次划分为
1, n-1, 第二次为 1, n-2& , 第三次 1, n-3,
递归的层高就是n-1层,效率就是 N * (N-1)& =&
Ѳ(N2), 因此,在快速排序中获取基准点时,
一般都要改进下.有一种改进方法就是每是取的参照点是取p[low],&p[High],&p[(Low+High)/2],&
取这三个值中的中间值,这样分隔开的子序列就会更逼近使两个子序列个数相等, 更逼近NLog2N。
下面我们再来看一个例子:汉诺塔。
递归函数一般这样写:
void hanoi(int n,char one ,char
two,char three)
 &&&&if(n==1)&&
move(one,three);
  & else{
  &&hanoi(n-1,one,three,two);&&//
&需要递归n-1次的移动
  &&move(one,three);&&&&&&&&&&
//& 只需要移动1次
  &&hanoi(n-1,two,one,three);&
//& 需要 递归n-1次移动
&&&它时间效率又是怎么样的呢?
&&&从这里看,第一次的移动接口是一个常数,我们就可以认为是Ѳ(1)了,那它的递归层数是多少呢?
&&&很明显,每一次的调用都是减1的,且要移动两次,如上面标识我们可以得出递推公式:
&&&&&&&&&&&
Cn+1 = 2Cn + 1&, 当n为1时,
&&&我们通过变换求下Cn的通项:
Cn+1 = 2Cn +1
(Cn+1 +1) = 2(Cn + 1)
=& (Cn+1 +1)/(Cn + 1) = 2
&&&根据等比数列的通项公式an
= a1 * qn-1, C1 = 1
=& 2n-1& -
Ѳ (2n)。很大啊~~~~~&
或者这样证明:
&&& Cn = 1 +
= 1 + 2 + 22Cn-2
= 1 + 2 + 22 + 23 + ... +
&&&&&&&&这个为&首项为1,
末项为2n-1C1 比例系数为2的等比数列求和.
= 1(1-2n-1)/(1-2) = 2n-1 - 1
******************************************************************************************
以上是一种简化的求解递归函数时,分析其时间复杂度的方法。在这里,为防止误人子弟,我还是把官方的公式再简单解释下:
&&&&在分治算法中的三个步骤中,&我们假设分解和合并过程所用的时间分别为D(n),
C(n),&设T(n)为处理一个规模为n的序列所消耗的时间为子序列个数,每一个子序列是原序列的1/b,α为把每个问题分解成α个子问题,
则所消耗的时间为
=&&&&Ѳ(1)&&&&如果n&=c
(是n中一个可以直接求解的规模c。在上面两例中c都为1)
&&&&&&&&&&&&&&αT(n/b)
+ D(n) + C(n) 否则
& 在上面的例子中, 我们同样可以用这个公式来套下试试.
& 在快速排序中,α&是为2的, b也为2, 则分解(就是取参照点,可以认为是1),
合并(把数组合并,为n), 因此D(n) + C(n) 是一个线性时间Ѳ(n).
&&这样时间就变成了T(n) = 2T(n/2) +
Ѳ(n).
& 下面有点复杂了, 在每个层上的时间复杂度为:
第在一层上是cn(c为比较一次时所用的时间), 在第二层上时数组被分成了两部分, 每部分为
n/2,&则在第二层上时间为 c *&n/2 + c* n/2 =
cn, 同样在第三层上,&被分成了四部分,&时间为c*n/4 +
c*n/4 + c*n/4 + c*n/4 =
cn.&层高一共是按刚才说的是Log2n层,每一层上都是cn, 所以共消耗时间
cn * Log2n; 则总时间:
& cn * Log2n +
cn = cn(1+Log2n)& 即
Ѳ(nLog2n).
******************************************************************************************&
& 总结下, 我的总结的方法&&C *
是抓住了递归算法中的最关键的地方αT(n/b)而得出的结论. 因为大O法只需要关注次数最高的部分就可以了, 可以简化你的分析过程.
对于快速排序, C: 一个子项的处理时间Ѳ(n), D(n): 递归层数, 树高, Log2n,
所以最终的结果是:
Ѳ(nLog2n). 对于汉诺塔, C: 一个子项的处理时间
Ѳ(1), D(n): 递归层数, 树高,
2n-1,&故最终结果是:&
Ѳ(2n). 很快就得出了结论.
&下面我们来做一个具体实例. 来自己设计一个算法, 并评价下时间复杂度. 问题是这样的,
&其具体数据如下所示:
&&& 题目是:
当给你任意一TitleID值 x, 根据TitleID &-- ItemID
&-- ItemDetail 关系, 找出所有ItemDetailID值集合. 用代码写, 不用SQL.
假设主键与外键都已经是排过序的.假设 Title表记录条目数量为M, Item表条目数量为N, 而Detail表记录数量为K, 且K
&= 10N,&&N
&= 4M(只是表述一个数量关系, 没有其它意思. 就是想表达Detail表记录比较多,
而且还挺多的). Item表中的数据只挂在Title表中的叶子节点下.
当TitleID为5(北京)时,其在Item中明细为4(东城区),5(西城区),6(海淀区),
则ItemDetailID的集合应该是:&6(中关村),7(上地)。如果TitleID为2(中国)时,则结果就是:&1,2,3,4,5,6,7.&
&& 处理这个问题我们两种方案:
1.&先遍历ItemDetail表, 把Level为A的找出来,
对于每条符合的记录再判断是否属于选中的TitleID值x. 符合, 则把ItemID值记录下来
& 代码写法大概为:
& void GetDetailItemIDsByTitleID(const X:
while&对于每个条ItemDetail中的记录
detailRecord,&则:{&(0)
&&&&&&&在记录
detailRecord 中:
根据ItemID值&nItemID&在Item中找到TitleID值
if x1==X&则: 把detailRecord.ID加到结果中 (2)
&&&&&&&&&&
在Title表中根据PID递归判断x1是不是属于x的孩子,&
&&&&&&&&&&&&
则加把detailRecord.ID加到结果中&&
在这里我们假设Title表中的树高(PID层次)为d,&由于主键和外键是排过序的,&则计算结果如下:&
(0): Detail表记录为K, 故为K;
(1):在Item表中根据 nItem值找到x1的开销为Log2N;
(2):&常数, 不考虑
(3):&的递归层次为d, Title表记录数为M, 则开销为d *
最后的结果:
& K * (Log2N + d
*&Log2M) + c. c为把nItem加到结果中的时间,
不能把ID加重了, 我们用一个常量表示.
&时间复杂度我们可以表示为: Ѳ(K(Log2N + d
2.&先对Title递归,
对于每一个具体的记录,找出其明细,&代码大概如下
void GetDetailItemIDsByTitleID(const X: Integer){
&&if 如果X所指的标题为节子节点
直接处理标题ID为X的明细(X) (2)
&& while 对于所有的当前标题的明细
iTitleChildRecord记录 do (3)
GetDetailItemIDsByTitleID(iTitleChildRecord.ID) (4)
(1): 判断为叶子节点,看PID有没有为X的就可以了, Log2M;
(2): 直接处理明细,则从子目表中定位到TitleID记录Log2N,
假设平均一个标题下明细Item个数为y, 则为: Log2N + yLog2K
(3): Log2M
(4): 层数为d, 假设平均一个标题下子标题数为z, 则: d * z
最后:& d*z(Log2N + yLog2K)
我们来比较下:
& 1. K * (Log2N + d
&&2. d*z(Log2N +
yItemLog2K) + 2Log2M
1中我们只看 k * d * Log2M, 2中我们只看d * z * y *
Log2K 这样, 我们只需要关注
*&Log2M 和 z(标题下子标题个数)
* y(一条标题下条目个数) * Log2K 即可了. 之前的关系 K
&= 10N,&&N
&= 4M, 你应该知道结论了!
& 我举的这个例子, 在我们的项目中有经验数据,比如z 一般在
10以内(用我们的话说就是某一章下的节一般不过超过10个), y(一章节下挂的子目一般最多在50个).M最多为2000, 而K
一般都在在6万以上.在这种环境下, 第一种方案结果: 60000 * 11 = 66万, 第二种方案: 10 * 50 * 16 =
以上主要是讲解如何对一个比较复杂的算法进行时间复杂度分析, 比较算法的优劣. 关于上面的例子, 大家看看有什么高招,
看还有没有更好的办法?&学习ing
补充关于最后一个例子我认为目前最好的算法&日9:09:06
************
思路是把标题上的当前TitleID和子标题的ID放在Hash中, 然后再在Detail表中进行一次遍历.
这样函数的效率可以认为是线性的, 实现如下:
void GetDetailItemIDsByTitleID(const X: Integer){
& 创建一个哈希表oTitleHash, 是以TitleID为键Key
& 创建一个ItemID与TitleID对应的Hash: oItemHash,
Key为ItemID, Value为TitleID
通过一个递归函数对oTitleHash进行填充, 把X及其孩子填充到哈希表中
& RecursiveFillHashIDs(oTitleHash,
& // 遍历Item表,
对于TitleID存在于oTitleHash中的记录, 添加到oItemHash中
& for 对于Item表中的每一条记录 iItem do
&&& //如果
iItem这记录的titleID存在于oTitleHash中, 则添加
oTitleHash.FindNode(iItem.TitleID)&!=&Null
oItemHash.Add(iItem.ID, iItem.TitleID);
& for 对于ItemDetail中的每一条记录 iRecord do {
// 从iRecord记录中得到ItemID值 :
nItemID&在oItemHash表中查找是否存在
oItemHash.FindNode(nItemID)&!=&NULL
把nItemID添加到结果集中
&(1): 所消耗时间为递归层次 * 平均每个标题下的孩子数: d * z
&(2): 遍历所有的Item表记录: n
&(3): 哈希操作, 平均效率: 1
&(4): 遍历ItemDetail表中的记录: k
&(5): 哈希操作: 1
&故最后结果是: d*z + n * 1 + k*1 = d*z + n +
&按经验数据, d深度一般为4, z 为10个左右, k
为6万, n 为几百, 最终的结果就是6万左右, 取决于k的大小. 因此可以简单的认为效率为:
& &Ѳ(k), 是线性的.
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。分析一下算法时间复杂度_百度知道
分析一下算法时间复杂度
++j)++x;n;++i)for(j=i+1;j&=nvoid fun(int n){
int i,j,x=0;for(i=1;i&lt
A[j]与A[j+1]对换其中n为正整数;i&=1;=i;++j)
if(A[j]&--i)
for(j=1;j&lt程序段for(i=n-1
我有更好的答案
内层循环都要耗费n的时间,所以整个程序执行时间完成需要的时间和n^2是线性关系,时间复杂度是O(n^2)。如果你只用了一层循环,外层循环变量每自增一次。现在你用了两层循环,那么程序执行完毕所用的时间和n的大小线性正相关冒泡排序
sita(n^2)
又加了一道题目求解答
另外初学数据结构
求详细步骤
且不说你冒的对不对。分析复杂度:外层循环执行n-1次,内层执行i次,于是内层执行次数为(n-1)+(n-2)+...+1,求和得复杂度为n^2。注意内层就是一个判断语句,于是你n^2是比较的复杂度,交换的复杂度最坏就是每次比较都要交换,也是n^2。
你这是冒泡排序么?n^2
为您推荐:
其他类似问题
时间复杂度的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。}

我要回帖

更多关于 蚁群算法求解函数最值 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信