算法初步
Posted yaofan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法初步相关的知识,希望对你有一定的参考价值。
0. 从1加到100?
先写一个从1加到100的程序,如何写呢?
记刚学程序时的写法:
int i, sum = 0, n = 100;
for(i = 0; i < 100; i++)
{
sum += i;
}
printf("%d", sum);
大神高斯小学时的解法用程序实现:
int sum = 0, n = 100;
sum = (1 + n) * n / 2;
printf("%d", sum);
我们看到的这两种解决从1加到100的解决方法,就是算法。
1. 算法定义
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或者多个操作。
2. 算法的特性
- 输入输出:算法具有零个或者多个输入。对于多数算法来说,输入参数是必要的,但是对于打印“hello world!”这样的代码,就不需要参数。算法至少有一个或多个输出。倘若一个算法没有输出,那我们要它何用?当然输出方式可以是打印输出或者返回一个或多个值等。
- 有穷性:指算法在执行有限步骤后,自动结束而不是无限循环,并且每一个步骤在可以接受的时间内执行完成。这里的有穷也是有边界的,并不是说执行一个算法需要二三十年也是能完成的,那样黄瓜菜都凉了,意义不大了。
- 确定性:算法的每一个步骤都有确定意义的,不会出现二义性。
- 可行性:算法的每一步骤都必须是可行的,也就是说,每一个步骤都能执行有限次数后完成。
3. 算法效率的度量方法
3.1 事后统计法
通过设计好的测试程序和数据,利用计算机计时器对不同的算法编制的程序的运行时间进行比较,从而确定算法的效率高低。
3.2 事前分析估算法
在算法编制前,根据统计方法对算法进行估算。
算法效率的度量也就是对算法运行时间的度量,而一个程序的运行时间,主要依赖于算法的好坏和输入规模。
输入规模即输入量的多少。
看栗子:
第一种求和算法:
int i, sum = 0, n = 100; //执行1次
for(i = 0; i < 100; i++) //执行年n+1次
{
sum += i; //执行n次
}
printf("%d", sum); //执行1次
第二种求和算法:
int sum = 0, n = 100; //执行1次
sum = (1 + n) * n / 2; //执行1次
printf("%d", sum); //执行1次
显然,第一种算法执行了2n+3次,第二种算法执行了3次,两种算法的好坏显而易见。
4. 函数的渐进增长
举个例子:
相同的输入规模n,算法A做2n+3次操作,算法B做3n+1次操作。两个算法谁更快呢?
显然,答案不确定,当n=1时,算法B快些;当n=2时,两者相等;当n>2时,算法A快。
此时给出这样的定义,输入规模n在没有限制的情况下,只要超过一个数值N,这个函数就总是大于另一个函数,我们就称函数是渐进增长的。
函数的渐进增长:给定两个函数f(n)和g(n),如果存在一个整数N,
使得对于所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐进快于g(n)。
根据函数的渐进增长性我们可以得出:某个算法,随着n的增大,它会越来越优于另一个算法,或者越来越差于另一个算法。
5. 算法的时间复杂度
5.1算法时间复杂度定义
在进行算法分析时,语句总的执行次数T(n)是关于输入规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间度量,记作:T(n) = O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度。其中f(n)是问题规模n的某个函数。
5.2 大O阶的推导
大O阶的推导:
1.用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。
得到的结果就是大O阶。
5.3 常数阶O(1)
int sum = 0, n = 100; //执行1次
sum = (1 + n) * n / 2; //执行1次
printf("%d", sum); //执行1次
5.4 线性阶O(n)
int i;
for(i = 0; i < n; i++)
{
//时间复杂度为O(1)的程序步骤序列
}
5.5 对数阶O(logn)
int count = 1;
while(count < n)
{
count = count * 2;
//时间复杂度为O(1)的程序步骤序列
}
5.6 平方阶O(n2)
int i, j;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
//时间复杂度为O(1)的程序步骤序列
}
}
计算如下程序的时间复杂度:
int i, j;
for(i = 0; i < n; i++)
{
for(j = i; j < n; j++)
{
//时间复杂度为O(1)的程序步骤序列
}
}
当i=1时,内循环执行了n-1次;当i=n-1时,内循环执行了1次,我们可以推算出总的执行次数为:
n+(n-1)+(n-2)+(n-3)+……+1=n(n+1)/2=n2/2+n/2
用大O推导法,可得这段代码的时间复杂度为O(n2)
5.7 常见时间复杂度
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2?)<O(n!)
以上是关于算法初步的主要内容,如果未能解决你的问题,请参考以下文章
有人可以解释啥是 SVN 平分算法吗?理论上和通过代码片段[重复]