算法
#:a+b+c=1000,a**2 + b**2 = c**2
for a in range(1001):
for b in range(1001):
c = 1000 - a - b
if a+b+c == 1000 and a**2 + b**2 == c**2:
print(a,b,c)
衡量算法性能的好坏的方式:时间复杂度
时间复杂度:量化算法执行步骤的数量,评估执行程序所需的时间,时间复杂度越来越大,执行的效率越来越低
空间复杂度:评估执行程序所需的存储空间
大O记法来表示时间复杂度:
*将时间复杂度执行步骤数量对应表达式(2n+n**2)中最有意义的一项提取出来放置在O后里面的括号里即可
*O(n**2)
#1.乱序系列中的两两元素进行大小比较,将比较出较大的元素逐步向后偏移(序列中最大的值就已经偏移到最后了) # def sort(alist): # for i in range(len(alist)-1):#控制元素两两比较的次数 # if alist[i] > alist[i+1]: # alist[i],alist[i+1] = alist[i+1],alist[i] # return alist #2.将第一步的操作继续一次作用在前n个乱序的序列中 def sort(alist): for j in range(len(alist)-1): for i in range(len(alist)-1-j):#控制元素两两比较的次数 if alist[i] > alist[i+1]: alist[i],alist[i+1] = alist[i+1],alist[i] return alist alist = [3,8,5,7,6,2,1] print(sort(alist))
面向对象实例
栈:先进后出
#栈 class Stack(): #先进后出 #入栈操作:从栈顶向栈底添加元素 #出栈:从栈顶向栈底取元素 def __init__(self): #添加一个列表的属性,让其充当栈的容器 self.items = [] def push(self,item): self.items.append(item) def pop(self): return self.items.pop() def length(self): return len(self.items) def isEmpty(self): return self.items == [] stack = Stack() stack.push(1) stack.push(2) stack.push(3) print(stack.length()) print(stack.isEmpty()) print(stack.pop()) print(stack.pop()) print(stack.pop())
#队列 class Queue(): def __init__(self): self.items = [] #入队列操作:从队尾向对头添加元素 def enqueue(self,item): self.items.insert(0,item) #出队列:从对头取元素 def dequeue(self): return self.items.pop() def length(self): return len(self.items) def isEmpty(self): return self.items == [] q = Queue() for i in range(5): q.enqueue(i) for i in range(5): print(q.dequeue())
队列例题:烫手的山芋
分析: 一轮游戏山芋被传递了几次:6次
因为每一轮游戏都需要淘汰一个小孩,基于队列的机制,每次只可以将对头元素取出,所以,要保证,山芋每次传递后,都要在队头孩子手里(山芋不动,人动)
class Queue(): def __init__(self): self.items = [] #入队列操作:从队尾向对头添加元素 def enqueue(self,item): self.items.insert(0,item) #出队列:从对头取元素 def dequeue(self): return self.items.pop() def length(self): return len(self.items) def isEmpty(self): return self.items == [] kids = ['A','B','C','D','E','F'] queue = Queue() #将6个小孩入队列 for kid in kids: queue.enqueue(kid) #A是队头 while queue.length() > 1: #设计一轮游戏的实现 for i in range(6): #控制山芋在一轮游戏中传递的次数 popItem = queue.dequeue() #出队列 queue.enqueue(popItem)#入队列 queue.dequeue() print(queue.dequeue())
面试题:如何使用两个栈的数据结构实现队列先进先出的效果!
class Stack1(): def __init__(self): self.alist = [] self.alist2 = [] # 进栈 def append(self,item): self.alist.append(item) # 出栈-->入栈 def pop(self): res = self.alist.pop() # print(res) self.alist2.append(res) # 出栈 def pop2(self): res = self.alist2.pop() print(res) s1 = Stack1() l = [8,6,9,2,4,3] for i in l: s1.append(i) # print(i) for i in range(6): s1.pop() for i in range(6): s1.pop2()
百度: class Solution: def __init__(self): self.stack1 = [] self.stack2 = [] def push(self, node): # 进栈 self.stack1.append(node) def pop(self): # if self.stack2 == []: # return None # else: for i in range(len(self.stack1)): self.stack2.append(self.stack1.pop()) # 出栈-->进栈 out = self.stack2.pop() # for j in range(len(self.stack2)): # self.stack1.append(self.stack2.pop()) # print(self.stack2.pop()) return out s1 = Solution() for i in range(5): s1.push(i) for j in range(5): print(s1.pop())
如何使用两个队列的数据结构实现栈先进后出的效果!
class Queue(): def __init__(self): self.queueA=[] self.queueB=[] def push(self, node): self.queueA.append(node) # 进队 def pop(self): if len(self.queueA)==0: return None while len(self.queueA)!=1: self.queueB.append(self.queueA.pop(0)) # 出队 ---> 进队 self.queueA,self.queueB=self.queueB,self.queueA #交换是为了下一次的pop return self.queueB.pop() q1 = Queue() for i in range(5): q1.append(i) for j in range(5): print(q1.pop())
链表
1、链表和列表的区别是什么?
*列表内存分配是连续的,可以应用索引的机制
*链表内存分配是不连续的,没有索引机制
列表的弊端:
应用场景:需要高频对列表发起元素的添加和删除
当需要将添加元素或者删除元素后续的元素整体向前或者向后进行偏移移动,势必会消耗计算机的算力
链表的应用场景:高频进行元素的添加和删除
2、实现链表的数据结构(内存空间是不连续的)
封装两种不同形式的数据结构:
1)节点Node:存储单个的元素数据
class Node(): def __init__(self,item): self.item = item self.next = None n1 = Node(1)
2)链表Link:用于有序组织所有的节点
class Link(): # 构建一个空链表 def __init__(self): self.head = None link = Link()
3、链表的完整实现:
class Node(): def __init__(self,item): self.item = item self.next = None class Link(): # 构建一个空链表 def __init__(self): self.head = None # 每次都向链表的头部添加节点(insert(0)) def addByHead(self,item): node = Node(item) node.next = self.head # 将插入的节点指向原始的头节点 self.head = node # 新添加的节点就是头节点 # 遍历链表 def travel(self): cur = self.head # 定义一个变量cur,让其指向头节点 while cur: # 当cur.next为0时,循环结束 print(cur.item) # 输出cur所指向节点的值 cur = cur.next # cur向后偏移 # 向链表尾部添加节点 def append(self,item): node = Node(item) if self.isEmpty(): # 判断链表是否为空 self.head = node return # 链表非空时 cur = self.head # cur指向头节点 per = None # 永远指向cur前一个节点 while cur: # cur.next为空(无节点)时,循环结束 per = cur cur = cur.next per.next = node # 循环结束时,pre一定指向的是链表的最后一个字节 # 判断链表是否为空 def isEmpty(self): return self.head == None # 返回链表中节点的数量 def size(self): cur = self.head count = 1 while cur: cur = cur.next count +=1 return count # 向任意位置添加节点 def insertNode(self,item,pos): # pos为0,1,2类似索引位置 node = Node(item) if pos == 0: # 如果添加头节点 self.addByHead(item) return cur = self.head # 如果在节点间添加新节点 per = None # per永远指向cur的前一个节点 for i in range(pos): # 数值pos刚好为cur移动次数 per = cur cur = cur.next per.next = node node.next = cur # 删除指定节点 def removeNode(self,item): cur = self.head per = None # 如果删除头节点 if item == self.head.item: self.head = self.head.next return # 如果删除的不是头节点 while cur: per = cur cur = cur.next if cur.item == item: per.next = cur.next return link = Link() link.addByHead(1) link.addByHead(2) link.addByHead(3) link.addByHead(4) # link.insertNode(66,4) # link.append(5) # link.removeNode(4) link.travel() # link.size()
1、基本概念:
1)根节点:树状结构中最上层的那一个节点
2)左右叶子节点:一个节点分叉出左右两个子节点
3)子树:
*完整的子树:根节点和左右叶子节点组成
*不完整子树:根节点+左叶子节点
根节点+右叶子节点
根节点
4)如区分不同的子树:根据子树的根节点来区别不同的子树
class Node(): def __init__(self,item): self.item = item self.left = None self.right = None
3、完整功能代码
class Node(): # 创建节点 def __init__(self,item): self.item = item self.left = None self.right = None class Tree(): def __init__(self): self.root = None # 树的根节点初始化 def addNode(self,item): node = Node(item) #树空的时候 if self.root == None: self.root = node return #树为非空 cur = self.root node_list = [cur] # 将根节点存入列表 while node_list: pop_node = node_list.pop(0) # 每次取列表的第一个值 if pop_node.left != None:# 如果取出来值有左节点 node_list.append(pop_node.left) # 添加进列表 else: #如果左节点为空,则添加到值的左节点处 pop_node.left = node return if pop_node.right != None: #如果取出来的值有右节点 node_list.append(pop_node.right) else: # 如果右节点为空,则将值添加到右节点 pop_node.right = node return # 判断值是否存在二叉树中 def findNode(self,item): find = False # 初始值 cur = self.root node_list = [cur] # 将根节点存于列表中 while node_list: pop_node = node_list.pop(0) # 取列表的第一个值 if pop_node.item == item: find = True break else: if pop_node.left != None: #左节点不为空加入列表 node_list.append(pop_node.left) if pop_node.right != None:#右节点不为空加入列表 node_list.append(pop_node.right) return find def traval(self): # 遍历树 cur = self.root node_list = [cur] while node_list: pop_node = node_list.pop(0) print(pop_node.item) if pop_node.left != None:#左节点不为空加入列表 node_list.append(pop_node.left) if pop_node.right != None:#右节点不为空加入列表 node_list.append(pop_node.right) tree = Tree() for i in range(1,7): tree.addNode(i) print(tree.findNode(61))
4、二叉树的遍历
*广度遍历:上述代码的travel就是广度遍历(逐层遍历)
*深度遍历:要将一颗二叉树中所有的子树依次按照下述三种方法进行遍历即可(前中后序遍历是需要依次作用在每一颗子树中)
前序:根左右
中序:左根右
后序:左右根
对一个二叉树从低到高排序:
class SortTree(): def __init__(self): self.root = None # 向树中插入值,左节点存放比根节点小或相等的值,右节点存放比根节点大的值 def insertNode(self,item): node = Node(item) #树为空时 if self.root == None: self.root = node return #树为非空时 cur = self.root while True: #插入节点比比较的节点的值小,则插入到其左侧,否则插入到其右侧 if node.item >= cur.item: #往右插 if cur.right == None: cur.right = node return else:#右节点当作根节点继续比较 cur = cur.right else: #往左插 if cur.left == None: cur.left = node return else:#左节点当作根节点继续比较 cur = cur.left def middle(self,root): #中序遍历:左根右 if root == None: return self.middle(root.left) # 左 print(root.item) # 根 self.middle(root.right) # 右 tree = SortTree() alist = [3,8,5,7,6,2,1] for item in alist: tree.insertNode(item) tree.middle(tree.root)