循序渐进学习时间复杂度

一、浅谈算法

学习软件开发这么多年,常常听到程序=数据结构+算法,但是很多人对这句话提出质疑,因为实际项目开发的时候大部分人是做螺丝钉的角色,而且大部分甘于做螺丝钉的角色,就会认为实际项目,只是完成业务开发而已,去哪都是增删改查,数据结构根本用不到。我认为,算法和基本的数据结构是非常重要的,对于一个合格的程序猿来说,有时候我们没有涉及到,只是别人把需要的事情都给我们做了,比如的java版本的hashmap,采用红黑树的结构,提高了更多效率,软件开发高速发展的同时,编程的门槛也会越来越低,只有了解了最本质的才会不被技术淘汰。

算法的五大特性:

1.有穷性:不是数学,算法比较合理,每一步在规定时间内进行

2.确定性:每一条指令都有一个明确的含义

3.可行性:算法可以执行

4.输入0或者多个

5.输出 只有一个

算法设计的四大要求:

1.正确性

2.可读性

3.健壮性:容错能力,输入数据非法的时候,不会产生的输出结果

边界问题 (数组的长度的判断,非法字段,树Root是否为空)

4.效率和存储

注:1.研究算法的复杂度,侧重的是研究算法随着输入规模扩大增长量的一个抽象,而不是精确定位执行多少次
2. 不关心编译语言,不关心机器

所以我们应该用什么方式进行算法的度量方式呢?接下来我们聊聊时间复杂度

二、时间复杂度

1.概述

我们知道程序的效率可以称之为程序的时间复杂度,通俗点说就是算法执行的时间,所以将算法中基本操作的执行次数作为算法时间复杂度的度量。

比如:如何求1+2+..... n的结果

第一种:O(n)

int sum=0;
    for(int i=0;i<=n;i++){
      sum=sum+i;
    }

第二种:O(1)

    int i=0;
    int sum=0;
    sum =(1+n)*n/2;

上述的例子可以说明如果不同的策略对待同一个需求而已,时间复杂度是不一样的,算法的优化,时间复杂度越低也是算法优化的目的之一。

时间复杂度:算法中基本语句重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作:\(T(n)=O(f(n))\)表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称渐近时间复杂度。

函数的渐进增长:给定两个函数,f(n).g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,那么我们说f(n)的增长渐进快于g(n)

上面讨论的时间复杂度是官方解释,仔细可以看时间复杂度可以表示渐进函数的抽象形式即可。

2.时间复杂度的记法:

1.大O记号 (常用)

假设\(f(n)和g(n)\)的定义域是非负整数,存在两个正整数c和n0,使得n>n0的时候,\(f(n)≤c*g(n)\),则\(f(n)=O(g(n))\)。可见\(O(g(n))\)可以表示算法运行时间的上界。\(O(g(n))\)表示的函数集合的函数是阶数不超过\(g(n)\)的函数。

例如:\(f(n)=2*n+2=O(n)\)

证明:
\(当n>3的时候,2*n?+2<3n,所以可选n0=3,c=3,则n>n0的时候,f(n)<c*(n),所以f(n)=O(n)。\)

现在再证明\(f(n)=2*n+2=O(n^2)\)

证明:\(当n>2的时候,2*n+2<2*n^2,所以可选n0=2,c=2,则n>n0的时候,f(n)<c*(n^2),所以f(n)=O(n^2)。\)

同理可证\(f(n)=O(n^a)\),a>1

2.?记号

\(f(n) > c*g(n)\)
?记号与大O记号相反,他可以表示算法运行时间的下界。\(?(g(n))\)表示的函数集合的函数是所有阶数超过g(n)的函数。

例如:\(f(n)=2*n^2+3*n+2=?(n^2)\)

证明:\(当n>4的时候,2*n^2+3*n+2>n^2,所以可选n0=4,c=1,则n>n0的时候,f(n)>c*(n^2),所以f(n)=?(n^2)。\)

同理可证\(f(n)=?(n),f(n)=?(1)\)

3.Θ记号

Θ记号介于大O记号和?记号之间。他表示,存在正常数c1,c2,n0,当n>n0的时候,\(c1*g(n)≤f(n)≤c2*g(n)\),则f\((n)=Θ(g(n))\)。他表示所有阶数与g(n)相同的函数集合。

4.小o记号

\(f(n)=o(g(n))当且仅当f(n)=O(g(n))且f(n)≠?(g(n))\)。也就是说小o记号可以表示时间复杂度的上界,但是一定不等于下界。

5.例子

假设f(n)=2n^2+3n+5,

则f(n)=O(n^2)或者f(n)?=?O(n^3)或者f(n)=O(n^4)或者……

f(n)=?(n^2)或者f(n)=?(n)或者f(n)=?(1)

f(n)=Θ(n^2)

f(n)?=?o(n^3)或者f(n)=o(n^4)或者f(n)=o(n^5)或者……


3.时间复杂度类型

1.常数阶

如上面的例子可以知道,执行次数是常数,可以定为O(1)

    int i=0;
    int sum=0;
    sum =(1+n)*n/2;

2.线性阶

如上述的例子可以知道,单次循环n,定为O(n)

int sum=0;
    for(int i=0;i<=n;i++){
      sum=sum+i;
    }

3.对数阶

下面代码就表示是\(O(logn)\)

  while (left <= right) {
            int mid = (left - right) / 2 + right;
            if (target == nums[mid]) {
                return mid;
            } else if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

4.函数调用

main方法调用外部方法,两个方法都是一层循环,则\(O(n^2)\)

int main(int argc, char *argv[])
{
for(int i=0;i<n;i++){
      fun(n);
    }
}
void fun(int count){
  for(int i=0;i<count;i++){
    printf();
  }
}

常见时间复杂度的比较:

$ O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)...<O(n!)<O(n^n)$

4. 时间复杂度的计算

1.计算规则

1) 加法规则?

\(T(n,m) = T1(n) + T2(n) = O ( max (f(n), g(m) )?\)

2) 乘法规则?

\(T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))?\)
\(O(n)*O(m)=O(n*m)\)

3)一个特例?

在大O表示法里面有\(T(n) = T1(n) * T2(n) = O ( c*f(n) ) = O( f(n) )\).?一个特例,如果\(T1(n) = O(cf(n))\), c是一个与n无关的任意常数,$T2(n) = O ( f(n) ) $则有?

总结:

1.用常数1取代所有的加法常数 t(n)=5 O(1)

2.修改后的函数中,只保留最高阶数

3.如果最高阶数的常数部分存在不是1,变成1。

比如:
\(T(n) = n^3 + n^2 + 29,此时时间复杂度为 O(n^3)。 T(n) = 3n^3,此时时间复杂度为 O(n^3)\)。

2.主定理

在算法分析中,主定理(英语:master theorem)提供了用渐近符号(大O符号)表示许多由分治法得到的递推关系式的方法。这种方法最初由Jon Bentlery,Dorothea Haken和James B. Saxe在1980年提出,在那里被描述为解决这种递推的“天下无敌法”(master method)。此方法经由经典算法教科书Cormen,Leiserson,Rivest和Stein的《算法导论》 (introduction to algorithm) 推广而为人熟知

解释: 上面的主定理就是根据递归式,我们需要找到它的时间复杂度,这里为了不区别其他的表示法,全部记为大O表示法,

例子1:

假设问题规模为N,某一个递归算法的时间程度记T(N),已知T(1) = 0,T(N) = T(N/2) + N,求用O表示该算法的时间复杂度?

分析:直接套用公式可知,a = 1, b = 2 ,f(n) = N , 主定理主要和\(n^{\log_b a}\)做比较,带入可得 \(n^{\log_b a}= 1\) 。
所以f(n)> \(n^{\log_b a}\) ,符合条件三,所以T(n) = O(n)。

例子2:

假设问题规模为N,某一个递归算法的时间程度记T(N),已知T(1) = 0,T(N) = 2T(N/2) + N/2,求用O表示该算法的时间复杂度?

分析:直接套用公式可知,a = 2, b = 2 ,f(n) = N/2 , 主定理主要和\(n^{\log_b a}\)做比较,带入可得 \(n^{\log_b a}= n\) 。
这里需要注意,f(n)和\(n^{\log_b a}\)做比较 ,比较的是它们的渐近增长率,所以f(n)= \(n^{\log_b a}\) ,符合条件二,都是一次函数,所以T(n) = O(nlogn)。

例子3:

求下面代码的时间复杂度:

void Hanoi(int n, char a, char b, char c)//a为原始柱,b为借助柱,c为目标柱
{
    if (n == 1)
    {
        Move(a, c);//只有一个盘子时直接移
    }
    else
    {
        Hanoi(n - 1, a, c, b);//将A柱子上n-1个盘子借助C柱子移到B上
        Move(a, c);//将A最后一个盘子移到C上
        Hanoi(n - 1, b, a, c);//将B柱子借助空A柱子移到C上
    }
}

分析:我们可以看出,用递归来解决汉诺塔问题是非常方便的选择,最后我们来分析一下汉诺塔问题的时间复杂度。
设盘子个数为n时,需要T(n)步,把A柱子n-1个盘子移到B柱子,需要T(n-1)步,A柱子最后一个盘子移到C柱子一步,B柱子上n-1个盘子移到C柱子上T(n-1)步。 得递推公式T(n)=2T(n-1)+1 。这个递推式子不符合主定理,所以需要运用高中的基础数学知识,
由递推式可以知道,凑方法,凑成等比数列,凑成通项公式 \(O(2^n)\)

例子4:

假设问题规模为N,某一个递归算法的时间程度记T(N),已知T(1) = 0,T(N) = T(N- 1) + N,求用O表示该算法的时间复杂度?

分析:首先要看主定理的限定的条件,b > 1 才可以执行这个主定理,这里需要\(T(N) = T(N- 1) + N 变成 T(N) - T(N- 1) = N。 可以T(1) ,T(2) .... T(N) 叠加后可以算出T(N)的通项公式。 可以计算O(n^2)\)

三、空间复杂度

类比于时间复杂度的讨论,一个算法的空间复杂度是指该算法所耗费的存储空间,计算公式计作:S(n) = O(f(n))。其中 n 也为数据的规模,f(n) 在这里指的是 n 所占存储空间的函数。一般情况下,我们的程序在机器上运行时,刨去需要存储程序本身的输入数据等之外,还需要存储对数据操作的「存储单元」。如果输入数据所占空间和算法无关,只取决于问题本身,那么只需要分析算法在实现过程中所占的「辅助单元」即可。如果所需的辅助单元是个常数,那么空间复杂度就是 O(1)。



吐槽:
我被博客园的markdown的编辑器弄疯了,花了我好长时间,我只是想排版好看一点,就用数学公式进行,而不是用图片的方式,结果博客园不支持$$ 解析,当然官方博客也给了解决方案,但是没用好吗?对于不是整段的数学公式是不起作用的 ,https://www.cnblogs.com/cmt/p/markdown-latex.html

正确做法:加入这个放入文章内
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>
,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言,就可以用$ 解析了,使用就是正常的。



参考:
https://www.jianshu.com/p/f4cca5ce055a

https://blog.csdn.net/qq_33274645/article/details/52688025

https://mp.weixin.qq.com/s/9njtnqfAatjmjPh4geETqA



原文地址:https://www.cnblogs.com/tojian/p/10012619.html

时间: 2024-10-17 18:06:00

循序渐进学习时间复杂度的相关文章

跟着杨中科循序渐进学习wpf(全)

第一季 C#编程基础 1.用C#编写一个10+20=?的小程序: public static voidMain(tring[] args) { int i1=10; int i2=20; int i3=i1+i2; Console.WriteLine(i3);           //也可用占位符来实现:Console.WriteLine("{0}+{1}={2}",i1,i2,i1+i2);在输出参数较多时候要用占位符 Console.ReadKey();             

经验之谈:循序渐进学习Java Web开发的五个阶段

Java web开发是Java开发中的主要方向,那什么是Java web开发呢,Java web开发就是基于J2SE的web应用程序开发,就是通过Java来解决互联网web应用的问题,互联网Web包含两个部分:web服务器和web客户端,Java语言在web服务器端的应用十分丰富,比如常用的Servlet.JSP等,总之,Java编程技术的到来给Web互联网的发展注入了一针强心剂,既然Java Web开发功能这么强大,那我们应如何循序渐进的学习Java Web开发呢?下面亦是美网络小编分为五个阶

python之循序渐进学习装饰器

python装饰器的定义:在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式称之为装饰器(Decorator) 装饰器的优点和用途: 1. 抽离出大量函数中与函数功能本身无关的的雷同代码并继续重用.2. 使用装饰器可以将函数"修饰"为完全不同的行为,可以有效的将业务逻辑正交分解,如用于将权限与身份验证从业务中独立出来.3. 如果一个函数需要一个功能,且这个功能可以被使用在很多函数上,或是函数并不是自己实现,那可以写个装饰器来实现这些功能.概况来说,装饰器的作用就是为已

循序渐进学习Linux--第二天更新

一.冯·诺依曼体系结构 CPU.内存.磁盘.输入设备.输出设备 二.cpu的架构 cpu组成包括:运算器.控制器.寄存器 PC兼容CPU架构:X86.X64位(一般兼容X86架构)手机的CPU架构:ARM架构(高通.华为.三星)服务器.工作站CPU架构:sun工作站 ultra-sparc cpu架构 solaris操作系统IBM power cpu架构 AIX操作系统HP alpha HP-UX 三.操作系统的概念 Application操作系统(系统调用.库调用)硬件 API(Applica

第五篇 Getting Started with ORACLE EBS(开始学习ORACLE EBS)

第一篇介绍了ERP软件是供应链管理软件.告诉你这个软件改善或提升企业管理的切入点和着力点.有了着力点才能给力. 第二篇介绍了什么是咨询以及咨询工作共通的章法,告诉了你咨询的套路是什么,就像练习一套拳,套路就是这样的,这些是形式的东西. 第三篇介绍了EXCEL和基于数据库的软件在数据处理方面的异同. 第四篇介绍了在国内做咨询你应该具备的一些基础理论常识. 从本篇也就是第五篇开始着手介绍一些循序渐进学习ORACLE EBS的知识.面向的读者是ORACLE EBS系统实施新手.并欢迎高手不吝批评纠正.

【数据结构与算法】时间复杂度的计算

算法时间复杂度的计算 [整理] 博客分类: 算法学习 时间复杂度算法 基本的计算步骤  时间复杂度的定义     一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数.记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号 ),简称时间复杂度. 根据定义,可以归纳出基本的计算步骤 1. 计算出基本操作的执行次

英语学习六大策略

为什么我们的英语学不好?我们投入的时间不可谓不多,天天学天天背:买的书不可谓少,天天看天天练:却结果往往是雄心开始,灰心丧气.古语有云:精诚石开,水滴石穿.学生们学英语都十多年了,为什么就打不开英语这个洋姑娘心房的门呢,为什么还停留在“哑巴英语”阶段呢?关键是我们没有抓住学习的关键点!   学英语,表面上看好像就是“听说读写”,而其实听说读写仅是语言能力的外在表现,只是语言的四大基本运用.比如英语口语,它是发音.词汇.造句的组合:比如英语写作,它是英语词汇.造句.思维方式的组合:比如英语阅读,它

如何学习新技术、团队技术选型时要注意些什么

首先,要说明的是,这里的“新”不一定是指时间上的新,在后文中,也可能是指,对于个人(或者团队)来说是“新的”,就是说,这个东西,即使出现了很久,应用广泛,但是个人(团队)没有使用过,那么也可以说是“新”的. 本文地址:http://www.cnblogs.com/xybaby/p/8655593.html 为什么要学习新技术 计算机知识日新月异,经常会涌现出新的语言.框架.思想.虽然说这些东西不一定都是从0到1的创造发明,也许只是微创新,或者将某个领域的思想用到了新的领域.不管怎么样,都能开阔思

C++ 读取txt文本内容,并将结果保存到新文本

循序渐进学习读文件 1 // readFile.cpp : 定义控制台应用程序的入口点. 2 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include <fstream> 7 #include <string> 8 using namespace std; 9 10 //引申:文件拷贝 11 void fileCopy(string file1,string file2){ 12 ifstrea