算法 介绍

一.算法的概念
1.概念:

算法是计算机处理信息的本质:计算机程序是通过1个算法来告诉计算机执行指定任务的步骤
算法处理信息时,通常会从输入设备或数据的存储地址读取数据,并把结果写入输出设备或存储地址
算法是独立存在的解决问题的方法和思想,对于算法而言,实现的语言并不重要,重要的是思想
算法可以有不同的语言描述实现版本(如C++描述/Python描述),后文将使用Python进行描述实现

2.算法的5大特性:

1.输入:算法有0/多个输入          2.输出:算法至少有1个输出 
3.有穷性:算法在有限的步骤后会自动结束而不会无限循环,并且每个步骤可在可接受的时间内完成 
4.确定性:算法中的每步都有确定的含义,不会出现二义性 
5.可行性:算法的每步都是可行的,也就是说每步都能通过执行有限次来完成

二.衡量算法的效率
1.执行花费的时间:

实现算法程序的执行时间可以反应出算法的效率,即算法的优劣

问题:程序的运行离不开计算机环境(包括硬件和OS),这些环境因素会影响程序的执行时间
因此,单纯依靠运行的时间来比较算法的优劣并不客观准确

2.时间复杂度
(1)时间复杂度:

假设存在函数g(n),使得算法A处理规模为n的问题所用的基本操作数/时间为T(n)=g(n)
则称g(n)为A的时间复杂度,记为T(n),但通常使用"大O记法"来表示
由于每个基本操作的用时固定,2种记法的T(n)之间至多只相差1个常系数

假定计算机执行算法的1个基本操作的用时是1个时间单位,那么有多少个基本操作就代表会花费多少个时间单位
在不同计算机环境中,确切的单位时间不同,但算法需要进行多少个基本操作(即花费多少个时间单位)大体相同
因此用算法所需的基本操作数衡量其时间效率,可以忽略计算机环境的影响而客观地反映算法的优劣,通常使用这种

#示例:
如果a+b+c=1000,且a^2+b^2=c^2(a,b,c均为自然数),如何求出所有a,b,c可能的组合?
#法1:
for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a**2+b**2==c**2 and a+b+c==1000:#本行视为1步
                print("a,b,c:%d,%d,%d"%(a,b,c))#本行视为1步
T1(1000)=2*1000^3          T1(n)=2*n^3
#法2:
for a in range(0,1001):
    for b in range(0,1001-a):
        c=1000-a-b#本行视为1步
        if a**2+b**2==c**2:#本行视为1步
            print("a,b,c:%d,%d,%d"%(a,b,c))#本行视为1步
T(1000)=3*1000*1001/2          T(n)=3*n*(n+1)/2=(3*n^2)/2+3*n/2

(2)大O记法:

对单调的整数函数f(n),如果∃整数函数g(n)和实常数c>0,使对充分大的n总有f(n)<=c*g(n)
就说g(n)是f(n)1个渐近函数(忽略常数),记为f(n)=O(g(n))
也就是说,在极限意义下,f(n)的增长速度受到g(n)的约束,亦即f(n)与g(n)的特征相似
这样,就称O(g(n))为算法A的渐进时间复杂度,简称时间复杂度,即考察n→∞时的情况

对算法的时间/空间性质,最重要的是其数量级和趋势,这些是分析算法效率的主要部分
而计量算法基本操作数量的规模函数中的常系数和低阶项可以忽略不计
如:可以认为3*n^2100*n^2属于同1个量级,如果2个算法的时间复杂度分别为这2个函数,就认为它们的效率"差不多",都为n^2#示例:
如果a+b+c=1000,且a^2+b^2=c^2(a,b,c均为自然数),如何求出所有a,b,c可能的组合?
#法1:
for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a**2+b**2==c**2 and a+b+c==1000:#本行视为1步
                print("a,b,c:%d,%d,%d"%(a,b,c))#本行视为1步
T1(1000)=2*1000^3=O(1000^3)     T1(n)=2*n^3=O(n^3)
#法2:
for a in range(0,1001):
    for b in range(0,1001-a):
        c=1000-a-b#本行视为1步
        if a**2+b**2==c**2:#本行视为1步
            print("a,b,c:%d,%d,%d"%(a,b,c))#本行视为1步
T(1000)=3*1001*1000/2=O(1000^2)     T(n)=3*(1+n)*n/2=(3*n^2)/2+3*n/2=O(n^2)

3.最坏时间复杂度:

最优时间复杂度:算法完成工作最少需要多少基本操作
最坏时间复杂度:算法完成工作最多需要多少基本操作
平均时间复杂度:算法完成工作平均需要多少基本操作

最优时间复杂度的价值不大,因为其反映的只是最乐观最理想的情况,没有参考价值
最坏时间复杂度提供了1种保证,表明算法在此量级的基本操作中一定能完成工作
平均时间复杂度,是对算法的1个全面评价,完整全面的反映了某个算法的性质
但这种衡量并没有提供保证,不是每个计算都能在这个量级内完成
而且,对于平均情况的计算,也可能因为应用算法的实例分布不均匀而难以进行
因此,我们主要关注最坏时间复杂度,没有额外说明时,下文的时间复杂度都指最坏时间复杂度

4.计算时间复杂度
(1)时间复杂度的几条基本计算规则:

1.基本操作:只有常数项,时间复杂度为O(1)
2.顺序结构:时间复杂度按加法计算
3.循环结构:时间复杂度按乘法计算
4.分支结构:时间复杂度取所有分支中的最大值
5.常系数和低阶项通常可以忽略,而只需要关心最高次项
6.函数不属于基本操作,而是对基本操作的封装,时间复杂度由源码决定
7.没有特别说明时,时间复杂度都指的是最坏时间复杂度

(2)常见时间复杂度:

O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^2logn) < O(n^3) < O(2^n) < O(n!) < O(n^n)

在这里插入图片描述
在这里插入图片描述
(3)一些测试和数据:

>>> from timeit import Timer
>>> def test1():
...     l = []
...     for i in range(1000):
...         l = l + [i]
...
>>> def test2():
...     l = []
...     for i in range(1000):
...         l.append(i)
...
>>> def test3():
...     l = [i for i in range(1000)]
...
>>> def test4():
...     l = list(range(1000))
...
>>> def test5():
...     l = []
...     for i in range(1000):
...         l.extend([i])
...
>>> def test6():
...     l = []
...     for i in range(1000):
...             l.insert(0,i)
...
>>> def test7():
...     l = []
...     for i in range(1000):
...             l.insert(i,i)
...
>>> t1 = Timer("test1()", "from __main__ import test1")
>>> print("concat ",t1.timeit(number=1000), "seconds")
concat  1.0837655000004816 seconds
>>> t2 = Timer("test2()", "from __main__ import test2")
>>> print("append ",t2.timeit(number=1000), "seconds")
append  0.058485100000325474 seconds
>>> t3 = Timer("test3()", "from __main__ import test3")
>>> print("comprehension ",t3.timeit(number=1000), "seconds")
comprehension  0.0286645000005592 seconds
>>> t4 = Timer("test4()", "from __main__ import test4")
>>> print("list range ",t4.timeit(number=1000), "seconds")
list range  0.013237400000434718 seconds
>>> t5 = Timer("test5()", "from __main__ import test5")
>>> print("extend ",t5.timeit(number=1000), "seconds")
extend  0.15172119999988354 seconds
>>> t6 = Timer("test6()", "from __main__ import test6")
>>> print("insert first ",t6.timeit(number=1000), "seconds")
insert first  0.2830551999995805 seconds
>>> t7 = Timer("test7()", "from __main__ import test7")
>>> print("insert last ",t7.timeit(number=1000), "seconds")
insert last  0.09288670000023558 seconds

效率:list(range())>[i for i in range()]>append()>insert() at last>extend()>insert() at first>concat

##############################################################################

>>> x = list(range(2000000))
>>> pop_zero = Timer("x.pop(0)","from __main__ import x")
>>> print("pop_zero ",pop_zero.timeit(number=1000), "seconds")
pop_zero  1.2205524000000878 seconds
>>> pop_end = Timer("x.pop()","from __main__ import x")
>>> print("pop_end ",pop_end.timeit(number=1000), "seconds")
pop_end  0.0001419000000169035 seconds

效率:pop() at last>pop() at first

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值