PYTHON基础篇(五)


  • 算法初识

    • 什么是算法
    • 二分查找算法

♣一:算法初识

A:什么是算法

根据人们长时间接触以来,发现计算机在计算某些一些简单的数据的时候会表现的比较笨拙,而这些数据的计算会消耗大量计算机资源,而且耗时,这个时候就有人对这类计算编写了一些策略,这些策略就是算法。这些策略会加快数据计算时间,大大减少计算机的资源消耗。

在长时间人们编写代码的工作中,一些优秀的算法就被流传下来,但是不是所有的算法都能实现目的一步到位的工作,它只能减少你的代码,提高工作效率,随着知识的不断积累,你会发现有更好的办法来完成算法所完成的事情。

B:二分查找算法

当有一个文件,文件里面都是数字,要写一段代码查找用户需要的数字在什么位置。之前的知识我们可能会使用循环去读取这个文件的每一行并最终找到这个数字所在的位置,此类方法可以达到目的,但是消耗了很多不必要的时间和资源。

这个其实也都想到了就是算法,上面的问题思路是这样的,我们首先把这个文件中数据的中间值取出来,让用户需要查找的数据这个这个中间值做比对,如果用户输入的数字大于这个中间值,那么我就往后找,再取一次这个中间值,再做比较,这样以此类推直到找到这个数字,并取出这个数字所在的位置即可。

#二分查找算法:
#版本1:
l = [2,4,5,6,8,13,22,24,44,56,66,67,68,88,89,90,99]
def find(l,tag): #tag是用户输入要查找大数字
half_tag = len(l)//2 #取一半的下标,此处要使用整除,防止除不尽的情况 #假如中间值是44
if l[half_tag] < tag: #用取一半列表再去哥用户要找的数字比对
num_l = l[half_tag+1 :] #如果用户输入的数字大于一半的下标,那么就从44后面找,这个位置要加1,是因为44在大于的时候已经比对过了,要从56开始比对
#num_l = l[half_tag+1 :] #把上面切掉的一半数据赋予新的变量名。
find(num_l,tag) #从上面新变量里面再去找,用户输入的是不是大于或者小于列表,一直重复下去,直到找到数字取到下标
elif l[half_tag] > tag:
num_l = l[:half_tag] #如果小于,就从24往前找,这个时候就不用加1,这个是切片的顾头不顾尾的原则
#half_tag = len(num_l)//2
find(num_l,tag)
else:
print('找到了!',half_tag,l[half_tag]) #最后一种情况就是找到了,那就直接打印即可。 find(l,66)

二分查找算法版本1

从上面的版本1,我们初步的把整个我们想实现目的的大致过程给写了出来,但是会发现有问题,我们要取的数字下标在l列表里面,结果出来的下标是1,这个和实际的情况不相符,我们要找的数字66是在l列表里面,不是在num_l新列表里面,接下里进行优化。

l = [2,4,5,6,8,13,22,24,44,56,66,67,68,88,89,90,99]
def find(l,tag,start=0,end=len(l)): #既然上面我们发现错误点是在新列表里面找的,那么我们需要让代码不断的从原始的l列表里面找。
#那么就需要定义一个开始start和结束end,让下面的代码在l列表里面调整start和end的位置即可。
#half_tag=len(l)//2 如果还是使用len(l)//2的话,half_tag就会是一个新的列表,那么还是没有解决从l列表找的问题。
half_tag = (end - start)//2 + start #例如end表99的位置是20,start的值10,那么就是20-10/2=5,下标是5就不对了。
#下标是5就从l表前面去找了,所以要加一个start,这样取的就是l的中间值了。
if l[half_tag] < tag:
find(l,tag,start=half_tag+1,end=end) #当取出一半的列表之后,find读取到用户在l列表里面找,开始的位置是上面比较之后的结果
#结束位置就是l列表结束的位置。
elif l[half_tag] > tag:
find(l,tag,start=start,end=half_tag-1)
else:
print('找到了!',half_tag,tag) find(l,66)

二分查找算法版本2

版本2里面我们已经解决了每次从新列表取的bug了,但是还是存在问题,1:end这个参数有问题,2:返回值的问题,我们虽然取到了结果,但是这个结果不能用于其它代码去调用,功能单一了,3:要是用户找的数字不再l列表里面怎么办。

l = [2,4,5,6,8,13,22,24,44,56,66,67,68,88,89,90,99] #问题1:如果l列表在函数代码下面出现,find函数就会出现问题。
def find(l,tag,start=0,end=None): #要解决上面的问题,需要把end变成默认参数
end = len(l) if end is None else end #在通过三元运算符来返回end,当end是空的时候就返回len(l),否则返回end(用户传过来的指)
half_tag = (end - start)//2 + start
if start <= end: #在find函数内部不断在执行的时候,会不断给start,end传输新的指,那么如果函数里面出现开始的指大于或者等于结束指了。
#那么理论上就出现错误了,说明该数字就不存在表里面。
if l[half_tag] < tag:
find(l,tag,start=half_tag+1,end=end)
elif l[half_tag] > tag:
find(l,tag,start=start,end=half_tag-1)
else:
print('找到了!',half_tag,tag)
else:
print('找不到该数字') #当开始大于等于结束指了,就直接报错找不到
find(l,23)
#问题2:要是要找的数字不在l列表里面,find函数肯定会报错 # l = [2,4,5,6,8,13,22,24,44,56,66,67,68,88,89,90,99]
# def find(l,tag,start=0,end=None):
# end = len(l) if end is None else end
# half_tag = (end - start)//2 + start
# if start <= end:
# if l[half_tag] < tag:
# find(l,tag,start=half_tag+1,end=end)
# elif l[half_tag] > tag:
# find(l,tag,start=start,end=half_tag-1)
# else:
# return half_tag #如果我在此处使用return,他是直接把返回值给到了上一级的find,也就是判断l>tag地方的find,或者l<tag地方的find.
# #因为函数内部在调用find,而这个find是不能接受这个返回值的,也就等于函数在上面的if地方就结束了。
# #函数在if的位置结束了,也就不会走到else的地方了,那么加在此处的return就return的是一个空,自然得到的结果就是none了
# else:
# print('找不到该数字')
# find(l,23)
# #问题3:被查找到的数字不能被二次调用。 l = [2,4,5,6,8,13,22,24,44,56,66,67,68,88,89,90,99]
def find(l,tag,start=0,end=None):
end = len(l) if end is None else end
half_tag = (end - start)//2 + start
if start <= end:
if l[half_tag] < tag:
return find(l,tag,start=half_tag+1,end=end)
elif l[half_tag] > tag:
return find(l,tag,start=start,end=half_tag-1)
else:
return half_tag
else:
return '找不到该数字' #上面既然会出现大于,小于,等于,找不到四种情况,每种情况都有可能返回了指接收不了,那么我们
#每次调用的指都返回回去,这样最外层的find就不会中断继续执行了,整个find函数就可以继续执行了
ret=find(l,23)
print(ret)
#问题3:被查找到的数字不能被二次调用。

二分查找算法版本3

上面的二分查找算法是使用递归函数来完成的,经过上面的验证,我们队递归函数有又新的理解。

1:只要写递归函数,一定就需要结束的条件,而这个结束的条件就是你知道结果就应该要结束掉了;

2:返回值这个地方,需要看返回操作是在递归到第几层的时候发生的,返回了给了谁,如果这个返回值不是返回到最外层函数,调用的层面是接收不到的,所以说这个返回值一定要返回到最外层函数;

3:在实际的场景中,只要能用算法解决的事情,必定多多少少会用到递归函数,而且所以语言都有递归的概念;

4:递归函数,最好是从结果往前推。

def fib(x):
if x==1 or x==2:
return 1
return fib(x-1)+fib(x-2)
fib1=fib(6)
print(fib1)

斐波拉契递归函数

上面的斐波拉契函数正常我们要查询数字比较小的,很快就能查出来,但是要是查询80或者100等,就会发现很慢,这个是因为return fib(x-1) + fib(x-2),这里面调用了两次fib函数,这会导致函数执行效率大打折扣,从表面我们看到fib(x-1)就是fib(5),fib(x-2)就是fib(4),但是程序在执行的时候,是要先算出fib(5)=fib(x-1)也就是fib(4),fib(4)=fib(x-1)也就是fib(3),就这样一层层的算到初始值1+1,如果是50,等于fib两边的数字先要分别以一种金字塔的形式分别算下去,这个就是导致程序执行慢的根本原因,所以说在递归函数,千万不要在内部调用多次。

def fib(x):
if x==2:
return 1,1
else:
a,b=fib(x-1) #这个else里面的代码就是解决上面fib调用多次导致效率低的关键,因为你在计算3的时候你肯定知道是1+2,那么在fib计算一次之后
#我就计算的数据赋值给两个变量。
return b,a+b#上面得到的两个值为了不要重复计算我下一个指,我就把上一次计算的指返回去一个,例如:用户找4,那么就是fib(1)+fib(2),
#用户在查询5的时候,我已经把fib(4)和fib(2)+fib(3)准备好了,且返回给了上一层的a,b两个变量,等于a,b重新被赋值了。
print(fib(3)) 解决查询的值会显示两位的问题
def fib(x,l=[0]):
l[0]+=1
if x==1 or x==2:
l[0]-=1
return 1,1
else:
a,b=fib(x-1)
l[0]-=1
if l[0]==0:
return a+b
return b,a+b
print(fib(10))

斐波拉契函数版本2

def fac(x):
if x==1:
return 1
return x*fac(x-1)
print(fac(5))

阶乘函数

5:递归函数一定要考虑到最大递归的998的问题,在之前的文章中有一定的介绍。

python基础篇(五)的更多相关文章

  1. Python基础篇(五)

    bool用于判断布尔值的结果是True还是False >>> bool("a") True >>> bool(3) True >>& ...

  2. Python基础篇(五)_文件和数据格式化

    Python基础篇_文件和数据格式化 文件的使用:文件打开.关闭.读写 文件打开:通过open()函数打开文件,并返回一个操作文件的变量. 使用语法:<变量名> = (<文件路径以及 ...

  3. python基础篇(六)

    PYTHON基础篇(六) 正则模块re A:正则表达式和re模块案例 B:re模块的内置方法 时间模块time A:时间模块的三种表示方式 B:时间模块的相互转换 随机数模块random A:随机数模 ...

  4. python基础篇(一)

    PYTHON基础篇(一) 变量 赋值 输入,输出和导入 A:输入 B:输出 C:导入 运算符 A:算数运算符 B:比较运算符 C:赋值运算符 D:位运算符 E:逻辑运算符 F:成员运算符 G:身份运算 ...

  5. python基础篇(二)

    PYTHON基础篇(二) if:else,缩进 A:if的基础格式和缩进 B:循环判断 C:range()函数和len()函数 D:break,contiue和pass语句 for,while循环 函 ...

  6. python基础篇(三)

    PYTHON基础篇(三) 装饰器 A:初识装饰器 B:装饰器的原则 C:装饰器语法糖 D:装饰带参数函数的装饰器 E:装饰器的固定模式 装饰器的进阶 A:装饰器的wraps方法 B:带参数的装饰器 C ...

  7. python基础篇(文件操作)

    Python基础篇(文件操作) 一.初始文件操作 使用python来读写文件是非常简单的操作. 我们使用open()函数来打开一个文件, 获取到文件句柄. 然后通过文件句柄就可以进行各种各样的操作了. ...

  8. 面试题之第一部分(Python基础篇) 80题

    第一部分(python基础篇)80题 为什么学习Python?==*== # 1. python应用于很多领域,比如后端,前端,爬虫,机器学习(人工智能)等方面,几乎能涵盖各个开发语言的领域,同时它相 ...

  9. python基础篇-day1

    python基础篇 python是由C语言写的: pass 占位符: del,python中全局的功能,删除内存中的数据: 变量赋值的方法: user,pass = 'freddy','freddy1 ...

随机推荐

  1. wordpress模板加载顺序汇总

    我们要创建一个新的wordpress模板需要先了解有哪些页面模板,这些页面模板的文件是什么?它们是怎么工作的?下面ytkah汇总了一些常用的wordpress模板结构方便大家查找 首页 首先WordP ...

  2. oracle中LPAD和RPAD函数的使用方法(加个人总结)

    今天看到两个没有见过的SQL中的函数,总结一下: 函数参数:lpad( string1, padded_length, [ pad_string ] ) 其中 string1:源字符串 padded_ ...

  3. Import declarations are not supported by current JavaScript version

    原因为:不支持当前的js版本,在perference中进行设置javascript的版本即可 注意:在perference中进行更改,而不是defeaut perference,快捷键操作为:comm ...

  4. LeetCode 785. Is Graph Bipartite?

    原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...

  5. docker 下载安装镜像

    docker安装成功后. 1.搜索镜像 # docker search java 可使用 docker search命令搜索存放在 Docker Hub(这是docker官方提供的存放所有docker ...

  6. packr 方便的潜入静态资源文件到golang 二进制文件中

    类似的工具以前有介绍过statik,今天使用的工具是packr 也是很方便的golang tools 安装 go get -u github.com/gobuffalo/packr/packr 或者我 ...

  7. Bacteria(优先队列)

    题目链接:http://codeforces.com/gym/101911/problem/C 问题简述:给定n个细胞以及每个细胞的大小,相同的细胞能进行融合,如果能融合到只剩1个细胞则输出需要额外增 ...

  8. mac 下的 tree 命令 终端展示你的目录树结构

    相信很多使用过Linux的用户都用过tree命令,它可以像windows的文件管理器一样清楚明了的显示目录结构.mac 下使用 brew包管理工具安装 tree 前提:安装了homebrew(安装指令 ...

  9. Comparison of SIFT Encoded and Deep Learning Features for the Classification and Detection of Esca Disease in Bordeaux Vineyards(分类MobileNet,目标检测 RetinaNet)

    识别葡萄的一种虫害,比较了传统SIFT和深度学习分类,最后还做了目标检测 分类用的 MobileNet,目标检测 RetinaNet MobileNet 是将传统深度可分离卷积分成了两步,深度卷积和逐 ...

  10. [内网渗透]HASH获取与HASH传递

    0x01 PTH简介 PTH,即Pass-The-Hash,首先我们来说下为什么要使用HASH传递,一是在目标机>=win server 2012时,lsass.exe进程中是抓不到明文密码的, ...