“算法和数据结构可以认为是绝对代码能力和耐心努力的一种证明”
一、python
2021【7.19】菜鸟教程数据类型
【8.10】list和数组的区别
10.28 通过变量名[索引值 : 索引值 : 步长] ———— 进行切片
11.7 List数据前面加‘*’表示将List拆分为独立的参数
11.12 list[左闭,右开] 与n=len(list)+1结合
【8.20】集合
【8.23】迭代器与生成器
【10.5】enumerate
【10.28】类
【10.30】字典
【2.10】易化AI
类:
动态的属性,静态的方法
self就是p,指向对象
class Person: #//定义类(只是想法)
name = 'lili' #//类属性
def talk(self): #//类行为(方法):形参self必须有,代表类的实例
print("can talk,my name is:",self.name);
p = Person() #//新建类的实例对象
p.talk() #//调用对象的方法(无参,但其实有参,它是隐藏的第一个实参,为类的实例)
print("name is",p.name) #//访问对象的属性
p.age=30 #//可动态添加(python是动态语言)
print("new age is",p.age)
函数做参数:
def fn(callback): #//函数参数: () -- 输入(做事需要什么东西, 如 callback)
print(callback,' type:',type(callback));
callback(); #//通过参数,间接调用函数 (回调函数)
def start():
print('start tv');
fn(start); #//函数做参数传入
【2.11】
类对象做函数参数
class Animal: #//定义一个类 Animal
name = "animal";
def breath(this):
print("can breath from water");
def air():
print("breath from air");
def change(o):
print("after change");
o.breath = air; //将air函数赋给传进来的类的breath方法
obj = Animal(); #//新建对象实例
print(obj.name);
obj.breath();
change(obj); #//对象做实参(引用类型传递 是地址传递,指向的是同一实体)
print(obj.name);
obj.breath();
函数的不定参数
*args 传入的参数是 元组类型
def test(*args):
print(args)
for i in args:
print(i)
test(1,2,3)
**kwargs 传入的参数是 dict 类型
def test(**kwargs):
print(kwargs)
keys = kwargs.keys()
value = kwargs.values()
print(keys)
print(value)
test(a=1,b=2,c=3,d=4)
【2.12】函数式编程:
尽量的少使用循环,忽略循环的影响
把重要的部分提取出来,修改函数代码即可
计算列表倍数
①以往编程
data = [ 1, 2, 3, 4, 5, 6]
res1 =[ ]
for n in data:
res1.append ( n * 2)
print (res1)
②列表解析式
res2 -[ n*2 for n in data ]
③函数式编程
def doubled(n) :
return n * 2
map ( doubled, data)
①匿名函数
把定义和调用放在一起
(lambda 输入n:表达式n×2)([ 1, 2, 3, 4, 5, 6])
②闭包
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
在网页注册账号时会应用到,填错时保留之前信息。
def outer(x):
def inner(y): #//inner是闭包,它引用外部的变量x
return x + y
return inner
a = outer(2)
print('result:',a(3)) #//驻留了前面2的信息
因为X是基础变量类型int,不能更改外部变量
将其改为列表或者字典就可以更改X信息
【2.13】
封装、继承
多重继承 尽量少使用,因为使得son与father,mother绑定在一起,增加了耦合性
class Father:
name ="father";
def football(self):
print(self.name,"play football good");
def talk(self):
print(self.name, "talk fast");
class Mother:
name ="mother"
def music(self):
print(self.name,"play music good");
def talk(self):
print(self.name, "talk slow");
class Son(Father,Mother): #//多重继承:儿子同时继承父母天赋
name ="son"
def draw(self):
print(self.name,"draw good");
s =Son();
s.football();
s.music()
s.draw()
s.talk() #talk fast//python没有二义性问题(c++有),父母都有时,以前一个为准
python 天生多态(动态语言,运行时动态绑定,边解析边执行),c++为静态语言
构造函数__init__
析构函数 销毁所创建的函数,释放资源
class Line:
name='a line'
def __init__(this,len=3): #//可选,无时,会有默认的
this.length = len
print('构造函数运行')
def __del__(this): #//可选,无时,会有默认的
print('析构函数运行,释放资源')
def show(this):
print('length is',this.length);
obj = Line() #//创建对象实例时,自动调用构造函数。
obj.show(); #//执行完自动析构(引用计数方式,进行垃圾回收)
【2.14】
函数的权限
在属性和方法前加下划线会限制其外部访问
class Girl: #//定义类(只是想法)
name = 'girl'
__age = 30 #//私有属性(以下划线开头)
def registerInfo(this):
print(this.name,'age is ',this.__age) #//私有属性仅内部能访问
def __getAge(this): #//私有方法(以下划线开头)
print('private __getAge is ',this.__age)
g = Girl()
g.registerInfo()
print(g.name)
g.__getAge() #//报错: 私有方法外部不能访问
print(g.__age) #//报错: 私有属性外部不能访问 (女孩年龄是秘密)
print(g._Girl__age) #//通过这种方式,外面也能够访问“私有”变量;调试中是比较有用的!
链式调用
class Person:
def name(self, str):
self.name = str
return self
def age(self, str):
self.age = str
return self
def show(self):
return self.name,self.age
obj=Person()
print(obj.name("ivan").age(37).show())
实际应用:用链式调用,实现多关键词的信息查询过滤
class Query():
def __init__(self):
self.query_condition = {}
def filter(self, **kwargs):
self.query_condition.update(kwargs)
return self
query = Query()
a = query.filter(name='lili').filter(age__gt=18, address='chengdu').filter(salary=12000)
print(query.query_condition) #//最后提交给数据库的查询信息
多线程
socket通信:
在python中调用C
#include <stdio.h>
int add_int(int, int);
int add_int(int num1, int num2){
printf("add num1+num2\n");
return num1 + num2;
}
使用命令gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c //在Linux编译生成动态库
//use.py
from ctypes import *
adder = CDLL('./adder.so') #//load c share lib
print(adder.add_int(4,5))
【2023.2.24】近几日开始准备实习的知识盲点
1.==和is区别
" is" (同一性运算符)是用来比较 a 和 b 是不是指向同一个内存单元,而"=="是用来比较 a 和 b指向的内存单元中的值是不是相等。
其实这是python解释器搞得鬼,具体是因为python的垃圾回收机制,这个垃圾回收机制会在之后的文章中详细介绍,至于出现上面这种现象是因为一个叫小整数对象池的东西,python为了优化速度,会把【-5,256】之间的数据提前存放在小整数对象池中,程序中只要用的【-5,256】之间的数据不会再重新创建一份,都是指向对象池中的同一份数据
2.引用、浅拷贝、深拷贝
①引用
a=[1,2,3]
b=a
改变b时a同时改变,是因为b和a是同一个地址
如何改变这种现象?就涉及到了拷贝技术
②浅拷贝
b=a.copy()
b=a[:]
以上两种方式改变b时不会改变a;
但是出现a是双层列表时就不行了,这时候使用深拷贝可以解决
③深拷贝
b=copy.copy(a)
3.函数有默认返回值None
4.可解析的数据类型
【2023.3.13】正则表达式
(1)限定符
?代表前面的字符可以出现0或者1次
*代表前面的字符可以出现0或者n次
+代表前面的字符必须出现1次以上
{}指定前面字符出现的次数,也可以是一个范围{1,n},后面的n也可以省略
()可以将多个字符括起来一起限定
(2)或运算符
a (cat|dog) 代表先匹配a 然后要么是cat出现要么是dog出现
(3)字符类
[abc]代表要求匹配的字符只能取自[]内
[ ^ 0-9]代表除了0-9之外的字符
(4)元字符
\b匹配一个隐式位置(字符与字符之间的位置)
\d 代表数字字符 = [0-9]
\w代表单词字符 =所有的Unicode单词字符,包含下划线和中文字符
\s代表空白字符,包含tab和换行符
\D代表非数字字符
\W代表非单词字符
.代表任意字符但是不包括换行符
^只会匹配行首 $只会匹配行尾
高级概念
贪婪(匹配结果尽可能多)和懒惰(匹配结果尽可能少)匹配
【3.13】不可变数据类型和可变数据类型
概念:指改变变量内容时,地址发没发生改变
不可变数据类型(当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,就称不可变数据类型):整形、字符串、元组
可变数据类型:集合、字典、列表
【4.13】
装饰器:
函数的前提知识:
可以调用函数
可以将函数赋值给其它变量
可以把它当成参数传给其它函数
可以在函数内定义一个函数,并做为返回值返回
装饰器就是在不影响原函数功能的情况下 给它添加一些功能(这个功能会被很多函数用到)。
"""
写两个不同语言说你好的函数,并且第一句是中文的欢迎!
"""
####第一个版本
def fun1(message :str):
print("你好!")
print("Hello "+message)
def fun2(message :str):
print("你好!")
print("Ciao "+message)
fun1("volcano")#output:你好! Hello volcano
#我们会发现以上两个函数都需要做重复的第一步,因此用Decorator来解决这一问题
####第二个版本
def my_decorator(func):#定义一个装饰器 传入函数名
def wapper(s): #装饰器的重复功能函数
print("你好!")
return func(s)#返回传入函数的执行结果
return wapper #返回wapper函数
def fun1(message :str):
print("Hello "+message)
def fun2(message :str):
print("Ciao "+message)
f = my_decorator(fun1)#my_decorator返回的是wapper函数(f就等于这个函数了),然后又将fun1作为参数先交给了func
f("volcano") #wapper接收volcano后先打印你好!,再将volcano传入fun1并返回Hello volcano
#output:你好! Hello volcano
#我们会发现上面最后的调用还是很麻烦,因此用@解决这一问题
####第三个版本
def my_decorator(func):#定义一个装饰器 传入函数名
def wapper(s): #装饰器的重复功能函数
print("你好!")
return func(s)#返回传入函数的执行结果
return wapper #返回wapper函数
def fun1(message :str):
print("Hello "+message)
def fun2(message :str):
print("Ciao "+message)
@welcome #相当于已经给fun1加上了my_decorator
fun1("volcano")#output:你好! Hello volcano
print(fun1) #output:<function my_decorator.<locals>.wapper at 0x000000000>可以看到这个函数的签名已经被装饰器包装起来了
一、小甲鱼
【2021.9.26】栈
【10.4】中缀表达变后缀表达
【10.5】分治
二、马士兵和左程云
【10.4】队列
三、python数据结构
【10.6】冒泡排序
快速排序 nlogn
【10.10】堆排序
二叉树的顺序存储:
①已知父节点序号i -->左孩子节点为2i+1
②已知父节点序号i -->右孩子节点为2i+2
③已知孩子节点序号为i -->父亲节点为(i-1)//2
大根堆:父亲大
小根堆:父亲小
堆得向下调整:左右都是堆,但是根节点不满足,通过一次向下调整可以变成一个合法堆
调整方法,选择最后一个节点放在顶点,然后向下调整
【10.12】堆排序代码
【10.26】挨个出数能够实现排序
对于解决topK问题复杂度也只是nlogK
【10.28】栈
【10.29】括号匹配
【10.31】队列
用列表实现队列不能循环存数,通过front/rear +1对maxsize取余可以实现循环
队空条件:rear == front
堆满条件: (rear+1)% maxsize == front
【11.1】链表
【11.4】哈希表
在直接寻址表的基础上引入哈希函数,让很大范围数的集合映射到一个很小的范围
当两个哈希函数结果值相同时 出现哈希冲突
为解决哈希冲突可以使用开放寻址法
使用拉链法解决哈希冲突,每一个位置放一个链表
【11.9】MD5是哈希表应用,百度网盘上传后会判断MD5值
树
树的度:最大节点数目
【11.15】二叉树
【11.16】二叉搜索树
迭代插入
【2022.7.7】链表、哈希表复习
【7.8】二叉搜索树
一个节点的左节点一定比当前节点值小
右节点一定比它大
【7.11】二叉搜索树的删除操作
①当删除节点没有叶子节点直接删除
②当删除的节点有1个孩子节点,将这个节点的孩子和父亲直接连接(设置成右子树)
特殊情况:当删除的节点是根节点时,重新设置孩子节点为根节点
③当删除的节点有2个孩子节点时,找到其右子树中最小节点删除(这个节点一定没有左孩子节点并且最多只有一个右孩子节点),并且替换当前节点。
【7.14】AVL树
是一颗自平衡的二叉搜索树,即是根的左右子树(都是平衡二叉树)的高度之差的绝对值不能超过1
插入一个节点可能会破坏AVL树的平衡,可以通过旋转操作来进行修正。
插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变。我们需要找出第一个破坏了平衡条件的节点,称之为K。K的两颗子树的高度差2。
不平衡的出现可能有四种情况:
AVL树的扩展应用 B树
贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断—个问题能否用贪心算法来计算。
可解决 ①找零问题
②数字拼接问题
③活动选择问题
【7.17】动态规划
在解决斐波那契数列这样的问题时,如果使用递归就会产生重复计算子问题(f4=f3+f2,f3=f2+f1重复计算f2)导致时间复杂度过高2^n
使用动态规划法:用一个数组将以前的计算结果都保存下来
我们解决动态规划问题一般分为四步:
1、定义一个状态,这是一个最优解的结构特征
2、进行状态递推,得到递推公式
3、进行初始化
4、返回结果
四、饲养员
数组
特点:读的快,写的慢
常用操作
a.insert(index,val)
a.remove(val)
a.pop(index)
a.pop()
链表
特点:写的很快,读的很慢
常用操作
linkedlist=deque()
linkedlist.append()
linkedlist.insert(index,val) O(N)
val=linkedlist[2] O(N)
linkedlist.index(99) O(N)
del linkedlist[index]
linkedlist.remove(val)
队列
peck()获取即将出队元素
pop()删除即将出队元素
哈希表=散列表
包括集合set
栈
用列表创建stack
【8.31】KMP
暴力查找模式串时 文本串匹配指针会回溯
aabaabaaf
aabaaf
KMP使用Next数组解决这一问题
前缀:包含首字母 不包含尾字母的所有子串
后缀:包含尾字母 不包含首字母的所有子串
最长相等前后缀:a(0)aa(1) aab(0) aaba(1) aabaa(2) aabaaf(0)
KMP遇到不匹配时,查询当前位置next为多少,然后跳到对应模式串位置开始继续匹配
这是因为next代表当前位置前的最长相等前后缀长度,也就是说模式串已经在前面匹配到前缀了
求next数组步骤:
①初始化指针以及第一个位置
使用i指向后缀尾 j指向前缀尾
②for i到模式串长度循环
③当i与j不相同也就是前后缀不同时 :j回溯到next[j-1]的位置
当i与j相同 也就是前后缀相同时:j++ 赋值next[j]=j++ i++
五、 数据结构与算法-青岛大学
投了一篇,接了个助教的工作;继续学习
【10.13】串
串也是一个线性结构
和前面学习的不一样的地方在于其中的每个元素只能是字符;不能是整数或者小数