算法的概念
算法是计算机处理信息的本质,因为计算机程序本质上是一个算法来告诉计算机确切的步骤来执行一个指定的任务。一般地,当算法在处理信息时,会从输入设备或数据的存储地址读取数据,把结果写入输出设备或某个存储地址供以后再调用。

算法是独立存在的一种解决问题的方法和思想。

对于算法而言,实现的语言并不重要,重要的是思想。

算法可以有不同的语言描述实现版本(如C描述、C++描述、Python描述等),我们现在是在用Python语言进行描述实现。

算法的五大特性

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

算法可以说是编程思想的核心,关于我个人的理解就是算法更像是一种解决问题的逻辑思维。可以理解为 程序=算法+数据结构.

首先先来一个简单的算法:
如果a+b+c=1000,且a^2 + b ^2= c ^2(a,b,c为自然数)如何求出所有a,b,c可能的组合
首先可以使用枚举法(一个个的数字去尝试)
思路:比方 a=0,b=0,c=0
第一次尝试:

#-*-coding:utf-8-*-
#auth:kokopop#如果a+b+c=1000,且a^2+b^2=c^2(a,b,c为自然数)如何求出所有a,b,c可能的组合
#枚举法(一个一个数去试)import time
start_time=time.time()for a in range(0,1001):for b in range(0,1001):for c in range(0,1001):if a+b+c==1000 and a**2+b**2==c**2:print("a,b,c:%d,%d,%d"% (a,b,c))end_time=time.time()
print("time:%d"%(end_time-start_time))
print("finished")
#每台机器执行的总时间不同,但是执行基本运算数量大体相同

运算结果:

/Users/kokopop/PycharmProjects/untitled3/venv/bin/python /Users/kokopop/PycharmProjects/untitled3/venv/01_abc.py
a,b,c:0,500,500
a,b,c:200,375,425
a,b,c:375,200,425
a,b,c:500,0,500
time:146
finishedProcess finished with exit code 0

第二次尝试:

#-*-coding:utf-8-*-
#auth:kokopop#如果a+b+c=1000,且a^2+b^2=c^2(a,b,c为自然数)如何求出所有a,b,c可能的组合
#枚举法(一个一个数去试)import time
start_time=time.time()for a in range(0,1001):for b in range(0,1001):c =1000-a-bif  a**2+b**2==c**2:print("a,b,c:%d,%d,%d"% (a,b,c))
end_time=time.time()
print("time:%d"%(end_time-start_time))
print("finished")
#每台机器执行的总时间不同,但是执行基本运算数量大体相同

运算结果:

/Users/kokopop/PycharmProjects/untitled3/venv/bin/python /Users/kokopop/PycharmProjects/untitled3/venv/01_abc.py
a,b,c:0,500,500
a,b,c:200,375,425
a,b,c:375,200,425
a,b,c:500,0,500
time:1
finishedProcess finished with exit code 0

由此可见第一种的三个for 循环的运算模式的时间是远远大于第二种(c=1000-a-b)运算模式的,比方说一次的运算模式
来看第一次运算:

#     for a in range(0,1001):
#     for b in range(0,1001):
#         for c in range(0,1001):
#             if a+b+c==1000 and a**2+b**2==c**2:
#                 print("a,b,c:%d,%d,%d"% (a,b,c))

三次的for循环的时间复杂度是100010001000,每次去找适配a+b+c=1000,都需要到1000个数里面去读,看是否适配,再加上if语句和print打印的2次,可以总结为(假设T是时间复杂度):
那么T=1000*1000*1000*2>T(n)=n^3*2>T(n)=k*n^3(k是常数项)
但是往往k在采用O的时候是可以被忽略的,因为无论是 n^3还是n^2他的变化曲线趋势是差不多的,而第二种运算模式由此看见即T(n) = O(n*n*(1+1)) = O(n*n) = O(n2)其余的几步k常数项的运算忽略掉

执行时间反应算法效率

对于同一问题,我们给出了两种解决算法,在两种算法的实现中,我们对程序执行的时间进行了测算,发现两段程序执行的时间相差悬殊(214.583347秒相比于0.182897秒),由此我们可以得出结论:实现算法程序的执行时间可以反应出算法的效率,即算法的优劣。

单靠时间值绝对可信吗?

假设我们将第二次尝试的算法程序运行在一台配置古老性能低下的计算机中,情况会如何?很可能运行的时间并不会比在我们的电脑中运行算法一的214.583347秒快多少。

单纯依靠运行的时间来比较算法的优劣并不一定是客观准确的!

程序的运行离不开计算机环境(包括硬件和操作系统),这些客观原因会影响程序运行的速度并反应在程序的执行时间上。那么如何才能客观的评判一个算法的优劣呢?

时间复杂度与“大O记法

我们假定计算机执行算法每一个基本操作的时间是固定的一个时间单位,那么有多少个基本操作就代表会花费多少时间单位。算然对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响而客观的反应算法的时间效率。

对于算法的时间效率,我们可以用“大O记法”来表示。

“大O记法”:对于单调的整数函数f,如果存在一个整数函数g和实常数c>0,使得对于充分大的n总有f(n)<=c*g(n),就说函数g是f的一个渐近函数(忽略常数),记为f(n)=O(g(n))。也就是说,在趋向无穷的极限意义下,函数f的增长速度受到函数g的约束,亦即函数f与函数g的特征相似。

时间复杂度:假设存在函数g,使得算法A处理规模为n的问题示例所用时间为T(n)=O(g(n)),则称O(g(n))为算法A的渐近时间复杂度,简称时间复杂度,记为T(n)

比如:
T(n)=k*g(n)
而g(n)=n^3
则g(n)是T(n)的渐近函数

如何理解“大O记法”

对于算法进行特别具体的细致分析虽然很好,但在实践中的实际价值有限。对于算法的时间性质和空间性质,最重要的是其数量级和趋势,这些是分析算法效率的主要部分。而计量算法基本操作数量的规模函数中那些常量因子可以忽略不计。例如,可以认为3n2和100n2属于同一个量级,如果两个算法处理同样规模实例的代价分别为这两个函数,就认为它们的效率“差不多”,都为n2级。

最坏时间复杂度

分析算法时,存在几种可能的考虑:

算法完成工作最少需要多少基本操作,即最优时间复杂度
算法完成工作最多需要多少基本操作,即最坏时间复杂度
算法完成工作平均需要多少基本操作,即平均时间复杂度
对于最优时间复杂度,其价值不大,因为它没有提供什么有用信息,其反映的只是最乐观最理想的情况,没有参考价值。

对于最坏时间复杂度,提供了一种保证,表明算法在此种程度的基本操作中一定能完成工作。

对于平均时间复杂度,是对算法的一个全面评价,因此它完整全面的反映了这个算法的性质。但另一方面,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。而且,对于平均情况的计算,也会因为应用算法的实例分布可能并不均匀而难以计算。

因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。

时间复杂度的几条基本计算规则

基本操作,即只有常数项,认为其时间复杂度为O(1)
顺序结构,时间复杂度按加法进行计算
循环结构,时间复杂度按乘法进行计算
分支结构,时间复杂度取最大值
判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略
在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度

常见时间复杂度


练习: 时间复杂度练习( 参考算法的效率规则判断 )
O(5) 可见是 O(1)
O(2n + 1) O(n)
O(n²+ n + 1) O(n²)
O(3n³+1) O(n³)

Python其实是有内置类型性能分析

比如 timeit模块

timeit模块可以用来测试一小段Python代码的执行速度。

class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)

Timer是测量小段代码执行速度的类。

stmt参数是要测试的代码语句(statment);

setup参数是运行代码时需要的设置;

timer参数是一个定时器函数,与平台有关。

timeit.Timer.timeit(number=1000000)

Timer类中测试语句执行速度的对象方法。number参数是测试代码时的测试次数,默认为1000000次。方法返回执行代码的平均耗时,一个float类型的秒数。

list的操作测试

#-*-coding:utf-8-*-
#auth:kokopop
from timeit import Timer
li1=[1,2]
li2=[23,5]
li=li1+li2
li=[i for i in range(10000)]#列表生成器
li =list(range(10000))#python2当中的range返回的直接是列表对象,python3中的range返回的是可迭代的对象
def test1():li = []for i in range(10000):li.append(i)
def test2():li =[]for i in range(10000):# li=li+[i]li+=[i]
def test3():li =[i for i in range(10000)]def test4():li =list(range(10000))def test5():li =[]for i in range(10000):li.extend([i])#append只能添加接收元素,extend是吧列表的所有东西都追加进去,必须接收列表或者可遍历对象timer1=Timer("test1()","from __main__ import test1")
print("append:",timer1.timeit(1000))timer2=Timer("test2()","from __main__ import test2")
print("+:",timer2.timeit(1000))timer3=Timer("test3()","from __main__ import test3")
print("[i for i in range]:",timer3.timeit(1000))timer4=Timer("test4()","from __main__ import test4")
print("list(range()):",timer4.timeit(1000))timer5=Timer("test5()","from __main__ import test5")
print("extend:",timer5.timeit(1000))def test6():li =[]for i in range(10000):li.append(i)#从队尾追加def test7():li =[]for i in range(10000):li.insert(0,i)#0代表始终从列表头部追加timer6=Timer("test6()","from __main__ import test6")
print("append:",timer6.timeit(1000))timer7=Timer("test7()","from __main__ import test7")
print("insert:",timer7.timeit(1000))

运算结果:

/Users/kokopop/PycharmProjects/untitled3/venv/bin/python /Users/kokopop/PycharmProjects/untitled3/venv/lib/02_list.py
append: 1.00561983
+: 0.9442914170000001
[i for i in range]: 0.4341080589999997
list(range()): 0.2611443040000001
extend: 1.265826139
append: 0.8424487359999997
insert: 18.451956641Process finished with exit code 0

注意:因为li=li+[i]所代表的是一个新的数组等于两个数组的叠加而在python中 我们前段代码中的li+=[i]python已经优化过所以运算速度是快于li=li+[i],我们可以看到下图中+的运算时间是138.435357294,所以在日常使用中,建议尽量不使用加法。

/Users/kokopop/PycharmProjects/untitled3/venv/bin/python /Users/kokopop/PycharmProjects/untitled3/venv/lib/02_list.py
append: 0.9296619429999999
+: 138.435357294
[i for i in range]: 0.43300338500000635
list(range()): 0.252829921
extend: 1.2557514289999858
append: 0.8375892130000011
insert: 20.143739622Process finished with exit code 0

List内置操作的时间复杂度

dict内置操作的时间复杂度

数据结构

我们如何用Python中的类型来保存一个班的学生信息? 如果想要快速的通过学生姓名获取其信息呢?

实际上当我们在思考这个问题的时候,我们已经用到了数据结构。列表和字典都可以存储一个班的学生信息,但是想要在列表中获取一名同学的信息时,就要遍历这个列表,其时间复杂度为O(n),而使用字典存储时,可将学生姓名作为字典的键,学生信息作为值,进而查询时不需要遍历便可快速获取到学生信息,其时间复杂度为O(1)。

我们为了解决问题,需要将数据保存下来,然后根据数据的存储方式来设计算法实现进行处理,那么数据的存储方式不同就会导致需要不同的算法进行处理。我们希望算法解决问题的效率越快越好,于是我们就需要考虑数据究竟如何保存的问题,这就是数据结构。

在上面的问题中我们可以选择Python中的列表或字典来存储学生信息。列表和字典就是Python内建帮我们封装好的两种数据结构。

概念

数据是一个抽象的概念,将其进行分类后得到程序设计语言中的基本类型。如:int,float,char等。数据元素之间不是独立的,存在特定的关系,这些关系便是结构。数据结构指数据对象中数据元素之间的关系。

Python给我们提供了很多现成的数据结构类型,这些系统自己定义好的,不需要我们自己去定义的数据结构叫做Python的内置数据结构,比如列表、元组、字典。而有些数据组织方式,Python系统里面没有直接定义,需要我们自己去定义实现这些数据的组织方式,这些数据组织方式称之为Python的扩展数据结构,比如栈,队列等。

算法与数据结构的区别

数据结构只是静态的描述了数据元素之间的关系。

高效的程序需要在数据结构的基础上设计和选择算法。

程序 = 数据结构 + 算法

总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体

抽象数据类型(Abstract Data Type):把我们原有的基于数据跟这个数据所支持的操作放在一起所形成的一个整体

抽象数据类型(ADT)的含义是指一个数学模型以及定义在此数学模型上的一组操作。即把数据类型和数据类型上的运算捆在一起,进行封装。引入抽象数据类型的目的是把数据类型的表示和数据类型上运算的实现与这些数据类型和运算在程序中的引用隔开,使它们相互独立。

最常用的数据运算有五种:
插入
删除
修改
查找
排序

什么是算法?数据结构与算法概念相关推荐

  1. 算法 | 数据结构与算法(代码版)

    ================================================= 博主github:https://github.com/MichaelBeechan 博主CSDN: ...

  2. C语言单链表实现FCFS算法,数据结构与算法复习题(含答案).doc

    <数据结构与算法>2015-2016学年第1学期考试复习题 选择题(下面各小题有一个正确答案,请将正确答案的编号填写在各小题的括号内). 1.在一棵具有5层的满二叉树中结点总数为( A ) ...

  3. 贪心算法设计作业调度c语言,贪心算法 - 数据结构与算法教程 - C语言网

    1.简介 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解. 贪心算法不是对所有问题都能得到整体最优 ...

  4. 算法 数据结构——收纳箱算法???

    . 最近工作上有一个需求,需要将图片打包成图集,以便于让资源更紧凑,利用率更高,提升性能,游戏行内的同志应该很熟练这个操作.通常我们需要用一个app来完成这项工作,最出名的莫过于Texture Pac ...

  5. 二叉树的建立和遍历算法 - 数据结构和算法47

    二叉树的建立和遍历算法 让编程改变世界 Change the world by program   有童鞋会说,我们上节课研究这么多遍历的方法干啥呢?聪明的鱼油们怎么看?! 对于二叉树,思路方面我们已 ...

  6. Day600601.马踏棋盘算法 -数据结构和算法Java

    马踏棋盘算法 图的深度优先DFS 回溯 八皇后问题.小老鼠找迷宫问题 一.介绍 二.思路分析 三.代码实现 package com.achang.algorithm;import java.awt.* ...

  7. Day595.普利姆算法 -数据结构和算法Java

    普利姆算法 一.问题引出 二.最小生成树 三.普利姆算法介绍 四.图解分析 五.代码实现 package com.achang.algorithm;import java.util.Arrays;/* ...

  8. 数据结构开山篇——数据结构和算法的基本概念

    绪论 文章目录 绪论 为甚要学习数据结构? 数据结构研究的内容 计算机进行数值计算的研究过程 计算机如何进行非数值运算 基本概念和术语 数据 数据元素 数据项 数据对象 数据构成 数据结构 数据类型 ...

  9. JavaScript数据结构和算法

    前言 在过去的几年中,得益于Node.js的兴起,JavaScript越来越广泛地用于服务器端编程.鉴于JavaScript语言已经走出了浏览器,程序员发现他们需要更多传统语言(比如C++和Java) ...

  10. JavaScript数据结构和算法 1

    前言 在过去的几年中,得益于Node.js的兴起,JavaScript越来越广泛地用于服务器端编程.鉴于JavaScript语言已经走出了浏览器,程序员发现他们需要更多传统语言(比如C++和Java) ...

最新文章

  1. 微软以后要是也开源也免费,java还竞争过.NET吗?
  2. java 动态数组的应用
  3. python数据结构之树
  4. c++远征之继承篇——隐藏,isa,虚析构函数
  5. MySQL关键字constra_mysql总结笔记(一)
  6. 小米手机困境,米粉伤心,黄牛伤钱
  7. gg修改器修改数值没有用怎么办_风灵月影是谁?风灵月影修改器大全
  8. 安装Oracle Webcenter 11.1.1.8.0并使用JDeveloper开发Portlet
  9. 【数据结构】二叉树的python实现
  10. ie下使用frameset布局导致跨域cookie丢失问题解决
  11. 再读《Java编程思想 》
  12. HYSPLIT 模型 传输轨迹 使用指南
  13. 【数模系列】01_聚类分析
  14. 海康威视2022内推 内推码
  15. WWF中Conditioned Activity Group的子Activity扩展CAG的WhenCondition属性代码解析
  16. 网页验证码识别实例VB.NET2019(二)
  17. 硕士学位论文写作分享
  18. Scratch 游戏项目学习法 —— 接苹果(五)把苹果放在顶端
  19. 那一夜,上海北京被逼到只能说:卧槽
  20. 软件测试工程师应届生工资,软件测试工程师薪水平均是什么水平?前景发展如何?...

热门文章

  1. 关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换
  2. jks bks 等的定义 如何将jks转化为bks的
  3. T6客户档案-供应商-存货名称不能录入空格--sql 怎么去掉最后一个字符
  4. OpenCL 学习step by step (11) 数组求和(reduction)
  5. 信修修:固态硬盘各式样,对比起来哪家强?
  6. 免费使用OriginPro学习版
  7. Ubuntu 12.04硬盘安装与U盘安装(图文)
  8. 梯度下降算法动图_一文读懂梯度下降算法
  9. vue展示日历 考勤展示_基于element-ui的日历显示当月考勤情况
  10. cvBoundingRect的用法