算法 初识
什么是算法 如何理解算法?
算法就是对问题进行处理且求解的一种实现思路或者思想。
- 一个常胜将军在作战之前都会进行战略的制定,目的是为了能够在最短的时间切成本消耗最低的情况下获取最终的胜利。如果将编码作为战场,则程序员就是这场战役的指挥官,你如何可以将你的程序可以在最短且消耗资源最小的情况下获取最终的执行结果呢?算法就是我们的策略!
什么是算法分析?
- 刚接触编程的学生经常会将自己编写的程序和别人的程序做比对,获取在比对的过程中会发现双方编写的程序很相似但又各不相同。那么就会出现一个有趣的现象:两组程序都是用来解决同一个问题的,但是两组程序看起来又各不相同,那么哪一组程序更好呢?
- a+b+c = 1000 a2 + b2 = c**2 (a,b,c均为自然数),求出a,b,c可能的组合?
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: print(a,b,c)
代码二
for a in range(0,1001): for b in range(0,1001): c = 1000 - a - b if a**2 + b**2 == c**2 and a+b+c==1000: print(a,b,c)
可以看出 相同的结果 不同的代码 时长不一样
评判程序优势的方法
- 消耗计算机资源和执行效率(无法直观)
- 计算算法执行的耗时(适当推荐,因为会受机器和执行环境的影响)
- 时间复杂度(推荐)
时间复杂度:
- 评判规则:量化算法执行的操作/执行步骤的数量
- 最重要的项:时间复杂度表达式中最有意义的项
- 大O记法:O(时间复杂度表达式中最有意义的项)
计算下列算法的时间复杂度
a=5 b=6 c=10 for i in range(n): for j in range(n): x = i * i y = j * j z = i * j for k in range(n): w = a*k + 45 v = b*b d = 33
3+3n**2+2n+1
O(n**2)
常见的时间复杂度:
- O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
数据结构
- 案例: 需要存储一些学生的学生信息(name,score),那么这些数据应该如何组织呢?查询某一个具体学生的时间复杂度是什么呢?(三种组织方式)
[ ['tom',100],['jay',99] ] #O(n)
[ ('tom',100),('jay',99) ] #O(n)
{ 'tom':{'score':100}, 'jay':{'score':100}, } #O(1)
如何测试代码性能?
-
timeit模块:该模块可以用来测试一段python代码的执行速度/时长。
-
Timer类:该类是timeit模块中专门用于测量python代码的执行速度/时长的。原型为:class timeit.Timer(stmt='pass',setup='pass')。
-
stmt参数:表示即将进行测试的代码块语句。
-
setup:运行代码块语句时所需要的设置。
-
timeit函数:timeit.Timer.timeit(number=100000),该函数返回代码块语句执行number次的
- 计算运行平局耗时
-
from timeit import Timer def test01(): alist = [] for i in range(1000): alist.append(i) def test02(): alist = [] for i in range(1000): alist += [i] def test03(): alist = [i for i in range(1000)] def test04(): alist = list(range(1000)) def test05(): alist = [] for i in range(1000): alist.insert(i, i) if __name__ == '__main__': timer = Timer(stmt='test01()', setup='from __main__ import test01') print(timer.timeit(1000)) timer = Timer(stmt='test02()', setup='from __main__ import test02') print(timer.timeit(1000)) timer = Timer(stmt='test03()', setup='from __main__ import test03') print(timer.timeit(1000)) timer = Timer(stmt='test04()', setup='from __main__ import test04') print(timer.timeit(1000)) timer = Timer(stmt='test05()', setup='from __main__ import test05') print(timer.timeit(1000)) ######################## 0.1200843300920747 0.09542515960902793 0.035514636978769026 0.022534339526118885 0.178243830964033
-
栈
先进后出的数据结构
栈顶,栈尾
Stack()创建一个空的新栈,他不需要参数,并返回一个空栈
push(item)将一个新项添加到栈的顶部,它需要item做参数并不不返回任何内容
pop()从栈中删除顶部的项,它不需要参数返回item,栈被修改
peek()从栈返回顶部项,但不会删除
isEmpty()测试栈是否为空,不需要参数,并返回布尔值
size()返回栈中的item数量,不需要参数,并返回一个整数
class Stack(): def __init__(self): self.items=[] def push(self,item): self.items.append(item) def pop(self): return self.items.pop() def peek(self): return self.items[-1] def isEmpty(self): return self.items==[] def size(self): return len(self.items) s=Stack() s.push('test1') s.push('test2') s.push('test3') print(s.pop()) print(s.pop()) print(s.peek())#返回栈的顶部 print(s.isEmpty())#判断是否为空 print(s.size())#返回栈的数量
网页回滚
s=Stack() def request(url): s.push(url) def back(): print(s.pop()) request('wwwbaidu1.com') request('www.baidu2.com') back() back() ###### www.baidu2.com wwwbaidu1.com
队列
先进先出
Queue()创建一个空的新队列,它不要参数
enqueue(item)将新项添加到队尾,它需要item作为参数
dequeue()从队首移除项,它不需要参数并返回item
isEmpry()查看队列是否为空 并返回布尔值
size()返回队列中的项书 并返回一个整数
class Queue(): def __init__(self): self.items=[] def enqueue(self,item): self.items.insert(0,item) def dequeue(self): return self.items.pop() def isEmpty(self): return self.items==[]#判断是否为空 def size(self): return len(self.items) q=Queue()#创建一个空对列 q.enquequ(1) q.enquequ(2) q.enquequ(3) print(q.dequeue()) print(q.dequeue())
1
2
烫手的山芋
烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。
规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
class Queue(): def __init__(self): self.items=[] def enqueue(self,item): self.items.insert(0,item) def dequeue(self): return self.items.pop() def isEmpty(self): return self.items==[]#判断是否为空 def size(self): return len(self.items) q = Queue() alist = ['a', 'b', 'c', 'd', 'e', 'f'] for i in alist: q.enqueue(i)#把6个孩子加入队列 while q.size() > 1:#循环队列大于一就跑 for i in range(6):#次数 kid = q.dequeue()#让对头的孩子退出队列 q.enqueue(kid)#在让加入队列 q.dequeue()#第6次之后 永久性退出循环 #结束之后 把这个孩子取出 print(q.dequeue())
双端队列
- 同同列相比,有两个头部和尾部。可以在双端进行数据的插入和删除,提供了单数据结构中栈和队列的特性
Deque()创建一个空的新deque,他不需要任何参数
addFront(item)将一个新项添加到deque的首部,他需要item参数
addRear(item)将一个新项添加到deque的尾部它需要iem参数
removeFront()从deque中删除首项,它不需要参数并返回item
removeRear()从deque中删除尾项,它不需要参数并返回item
isEmpty()测试deque是否为空,它不需要参数,并返回布尔值
size()返回deque中的项说,它不需要参数,并返回一个整数
class Deque():#创建一个空的deque def __init__(self): self.items = [] def addFont(self,item):#将一个新的项添加到deque首部 self.items.append(item) def addRear(self,item):#将一个新的项添加dequ尾部 self.items.insert(0,item) def removeFont(self):#删除首项 return self.items.pop() def removeRear(self):#删除尾项 return self.items.pop(0) def isEmpty(self):#测试是否为空 return self.items == [] def size(self):#返回deque中的项数 return len(self.items) def isHuiWen(word): ex=True q=Deque() for ch in word: q.addFont(ch)#双端队列从头部尾部添加都可以 while q.size() >1: if q.removeFont() != q.removeRear():#头部取出 尾部取出 ex=False break return ex print(isHuiWen('toot'))
计算机存储理解
- 指向:如果一个变量存储了某一块内存空间的地址,则表示该变量指向该块内存
- 引用:如果一个变量存储了某一块内存空间的地址,则该变量可以成为该内存的一个引用
顺序表
- 容器中存储的元素是有顺序的,顺序表的结构可以分为两种形式:单数据类型和多数据类型。
- python中的列表和元组就属于多数据类型的顺序表
相同类型属性的列表 存储结构
不相同类型属性的列表 存储结构
链表
相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理且进行扩充时不需要进行数据搬迁。
. is_empty():链表是否为空
. length():链表长度
. travel():遍历整个链表
. add(item):链表头部添加元素
. append(item):链表尾部添加元素
. insert(pos, item):指定位置添加元素
. remove(item):删除节点
. search(item):查找节点是否存在
add添加解
travel遍历
class Node(): def __init__(self, item): self.item = item self.next = None # 存储的链表中下一个节点的地址 class Link(): def __init__(self): # _head永远指向None或者第一个节点的地址 self._head = None def add(self, item): node = Node(item) node.next = self._head#Node的self.next self._head = node def travel(self): # cur存储的就是第一个节点的地址 cur = self._head while cur: print(cur.item) cur = cur.next link=Link() link.add(1) link.add(2) link.add(3) link.travel()
回顾:
def is_Empty(self):#判断联表是否为空 return self._head == None def size(self): length = 0 if self._head == None:#如果head是空 直接返回 return length #cur就是指向了第一个节点 cur = self._head while cur:#不为空循环 length += 1 cur = cur.next#一直向下查找 return length
append
def append(self,item): node = Node(item) #如果链表为空则执行如下操作 if self._head == None: self._head = node return cur = self._head#等于head头 pre = None while cur: pre = cur#上一个 cur = cur.next#下一个 pre.next = node#当前插入值 def search(self,item): ex = False cur = self._head while cur: if cur.item == item:#判断是否相等 ex = True break cur = cur.next#不断的往下查找 return ex
insert
def insert(self,pos,item): node = Node(item) if pos <= 0:#小于0add self.add(item) return if pos >= self.size():#大于等于链表的长度插入尾部 self.append(item) return cur = self._head pre = None for i in range(0,pos): pre = cur cur = cur.next pre.next = node node.next = cur
remove
def remove(self,item): cur = self._head pre = None if cur.item == item:#删除第一个节点 self._head = cur.next return while cur: pre = cur cur = cur.next#做遍历 if cur.item == item:#意味着是我们想删除的节点 pre.next = cur.next#从c2划到c4 break
总结:
class Node(): def __init__(self,item): self.item = item self.next = None #存储的链表中下一个节点的地址 class Link(): def __init__(self): #_head永远指向None或者第一个节点的地址 self._head = None def add(self,item): node = Node(item) node.next = self._head self._head = node def travel(self): #cur存储的就是第一个节点的地址 cur = self._head while cur: print(cur.item) cur = cur.next def is_Empty(self): return self._head == None def size(self): length = 0 if self._head == None: return length #cur就是指向了第一个节点 cur = self._head while cur: length += 1 cur = cur.next return length def append(self,item): node = Node(item) #如果链表为空则执行如下操作 if self._head == None: self._head = node return cur = self._head pre = None while cur: pre = cur cur = cur.next pre.next = node def search(self,item): ex = False cur = self._head while cur: if cur.item == item: ex = True break cur = cur.next return ex def insert(self,pos,item): node = Node(item) if pos <= 0: self.add(item) return if pos >= self.size(): self.append(item) return cur = self._head pre = None for i in range(0,pos): pre = cur cur = cur.next pre.next = node node.next = cur def remove(self,item): cur = self._head pre = None if cur.item == item: self._head = cur.next return while cur: pre = cur cur = cur.next if cur.item == item: pre.next = cur.next break
link = Link()
link.add(1)
link.add(2)
link.add(3)
link.append(4)
# link.insert(-2,'hello')
link.remove(3)
link.travel()