import operator
op = operator.add
from dataStructurewithPython.pythonds.basic.stack import Stack
from dataStructurewithPython.pythonds.trees.binaryTree import BinaryTree
def buildParseTree(fpexp):
fplist = fpexp.split()
pStack = Stack()
eTree = BinaryTree('')
pStack.push(eTree)
currentTree = eTree
for i in fplist:
if i == "(":
currentTree.insertLeft('')
pStack.push(currentTree)
currentTree = currentTree.getLeftChild()
elif i not in ['+','-','/','*',')']:
currentTree.setRootVal(int(i))
parent = pStack.pop()
currentTree = parent
elif i in ['+','-','/','*']:
currentTree.setRootVal(i)
currentTree.insertRight('')
pStack.push(currentTree)
currentTree = currentTree.getRightChild()
elif i == ")":
currentTree = pStack.pop()
else:
raise ValueError
return eTree
import operator
def evaluate(pareseTree):
opers = {'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}
leftc = pareseTree.getLeftChild()#缩小规模
rightc = pareseTree.getRightChild()
if leftc and rightc:
fn = opers[pareseTree.getRootVal()]
return fn(evaluate(leftc),evaluate(rightc))#递归调用
else:
return pareseTree.getRootVal()#基本结束条件
def preorder(tree):
if tree:
print(tree.getRootVal())
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
def postorder(tree):
if tree != None:
postorder(tree.getLeftChild())
postorder(tree.getRightChild())
print(tree.getRootVal())
def inorder(tree):
if tree != None:
inorder(tree.getLeftChild())
print(tree.getRootVal())
inorder(tree.getRightChild())
def preorder(self):
print(self.key)
if self.leftChild:#判断左子树是否存在
self.leftChild.preorder()
if self.rightChild:#判断右子树是否存在
self.rightChild.preorfer()
def postordereval(tree):
opers = {'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}
res1 = None
res2 = None
if tree:
res1 = postordereval(tree.getLeftChild())
res2 = postordereval(tree.getRightChild())
if res1 and res2:
return opers[tree.getRootVal()](res1,res2)
else:
return tree.getRootVal()
def printexp(tree):
sVal = " "
if tree:
sVal = '(' + printexp(tree.getLeftChild())
sVal = sVal + str(tree.getRootVal())
sVal = sval + printexp(tree.getRightChild()) + ')'
return sVal
二叉堆初始化
采用一个列表来保存堆数据,其中表首下标为0的项无用,但为了后面代码可以用到简单的整数乘除法,仍保留他.
堆的性质:在任何一条路径上,都是有一个有序的数列,而且最小要任何一个节点都比父节点大(任何一个节点都比子节点小)
class BinHeap:
def __init__(self):
self.heaplist = [0]
self.currentSize = 0
insert(key)方法
首先,为了保持“完全二叉堆”的性质,新key应该添加到列表末尾。
新key加到列表末尾,显然无法保持“堆”次序,需要将新key沿着路径来“上浮”到其正确位置
def percUp(self,i):
while i // 2 > 0:
if self.heaplist[i] < self.heaplist[i//2]:
temp = self.heaplist[i//2]
self.heaplist[i//2] = self.heaplist[i]
self.heaplist[i] = temp
i = i // 2
def insert(self,key):
self.heapList.append(key)#添加到末尾
self.currentSize = self.currentSize + 1
self.percUp(self.currentSize)#新key上浮
delMin()方法
移走整个堆中最小的key:根节点heapList[1]
为了保持“完全二叉树”的性质,只用最后一个节点来代替根节点,仍然破坏了“堆”次序
解决办法:将新的根节点沿着一条路径“下沉”,直到比两个子节点都小
下沉路径的选择:如果比子节点大,那么选择较小的子节点来交换下沉
def percDown(self,i):
while (i * 2) <= self.currentSize:
mc = self.minChild(i)
if self.heapList[i] > self.heapList[mc]:
temp = self.heapList[i]
self.heapList[i] = self.heapList[mc]#交换下沉
self.heapList[mc] = temp
i = mc#沿路径向下
def minChild(self,i):
if i * 2 +1 > self.currentSize:
return i * 2#唯一节点
else:#返回娇小的
if self.heapList[i*2]
buildHeap(lst):从无序表生成“堆”
用下沉法,能够将总代价控制在O(n)
def buildHeap(self,alist):
i = len(alist) // 2#从最后节点的父节点开始,因叶节点无需下沉
self.currentSize = len(alist)
self.heapList = [0] + alist[:]
print(len(self.heapList),i)
while (i >0):
print(self.heapList,i)
self.percDown(i)
i = i - 1
print(self.heapList,i)
ADT MAP中,可以采用不同的数据结构和搜索算法来保存和查找key,如有序表数据结构+二分搜索算法(O(long n)),散列表数据结构+散列及冲突解决算法(O(1))
ADT Map定义的操作如下:
Map():创建一个空映射,返回空映射对象;
put(key,val):将key-val关联对加入映射中,如果key已存在,将val替换旧关联值
get(key):给定key,返回关联的数据值,如不存在,则返回None
del:通过del map[key]的语句形式删除key-val关联
len():返回映射中key-val关联的数目
in:通过key in map的语句形式,返回key是否存在于关联中,布尔值
二叉查找树BST的性质
二叉搜索树的实现:节点和链接结构
class BinarySearchTree:#BST类
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.size
def __iter__(self):#可供迭代 for node in bst
return self.root.__iter__()
class TreeNode:#treeNode类
def __init__(self,key,val,left=None,\
right=None,parent=None):
self.key = key#键值
self.payload = val#包含的数据项,跟键值关联的数据
self.leftChild = left#左子节点
self.rightChild = right#右子节点
self.parent = parent#指向父节点,方便回溯操作
def hasLeftChild(self):#判断treeNode是否拥有左子节点
return self.leftChild
def hasRightChild(self):#判断treeNode是否拥有右子节点
return self.rightChild
def isLeftChild(self):#判断treeNode是否是父节点的左子节点
return self.parent and \
self.parent.leftChild == self
def isRightChild(self):#判断treeNode是否是父节点的右子节点
return self.parent and \
self.parent.rightChild == self
def isRoot(self):#判断treeNode是否是根节点
return not self.parent
def isLeaf(self):#判断treeNode是否是叶节点
return not (self.leftChild or self.rightChild)
def hasAnyChildren(self):#判断treeNode是否有子节点
return self.leftChild or self.rightChild
def hasBothChildren(self):#判断treeNode是否同时有左右子节点
return self.leftChild and self.rightChild
def replaceNodeData(self,key,value,lc,rc):#把treeNode的所有值更换
self.key = key
self.payload = value
self.leftChild = lc
self.rightChild = rc
if self.hasLeftChild():#如果有左子节点,那么左子节点的父节点也要更换
self.leftChild.parent = self
if self.hasRightChild():#如果有右子节点,那么右子节点的父节点也要更换
self.rightChild.parent = self
BST.PUT方法:put(key,val)方法,插入key构造BST
def put(self,key,val):
if self.root:
self._put(key,val,self.root)#在哪个为根节点的子树上插入key
else:
self.root = TreeNode(key,val)
self.size = self.size + 1
_put(key,val,self.root)的流程
def _put(self,key,val,currentNode):
if key < currentNode.key:
if currentNode.hasLeftChild():
self._put(key,val,currentNode.leftChild)
else:
currentNode.leftChild = TreeNode(key,val,parent=currentNode)
else:
if currentNode.rightChild():
self._put(key,val,currentNode.rightChild)
else:
currentNode.rightChild = TreeNode(key,val,parent=currentNode)
索引赋值
特殊方法:
def __setitem__(self, k, v):
self.put(k,v)
BST.get方法
在树中找到key所在的节点取到payload
def get(self,key):
if self.root:
res = self._get(key,self.root)#递归函数,找到节点
if res:
return res.payload#找到节点
else:
return None
else:
return None
def _get(self,key,currentNode):
if not currentNode:
return None
elif currentNode.key == key:
return currentNode
elif key < currentNode.key:
return self._get(key,currentNode.leftChild)
else:
return self._get(key,currentNode.rightChild)
索引取值和归属判断
def __getitem__(self, key):
return self.get(key)
def __contains__(self, key):
if self._get(key,self.root):
return True
else:
return False
迭代器
def __iter__(self):
if self:#如果根节点不为空,递归基本结束条件
if self.hasLeftChild():#如果左子树不为空
for elem in self.leftChild:#递归调用
yield elem
yield self.key#取根
if self.hasRightChild():#如果右子树不为空
for elem in self.rightChild:
yield elem
BST.delet方法
def delet(self,key):
if self.size > 1:#如果不止一个节点
nodeToRemove = self._get(key,self.root)#找到需要remove的节点
if nodeToRemove:
self.remove(nodeToRemove)
self.size = self.size - 1
else:
raise KeyError('Error,key not in tree')
elif self.size == 1 and self.root.key == key:#判断树上只有一个节点
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error,key not in tree')
def __delitem__(self, key):
self.delet(key)
if currentNode.isLeaf():#没有子节点的情况
if currentNode == currentNode.parent.leftChild:#如果其是左子节点
currentNode.parent.leftChild = None
else:
currentNode.parent.rightChild = None#如果其是右子节点
else:
if currentNode.hasLeftChild():
if currentNode.isLeftChild():#左子节点删除
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRigthChild():#右子节点删除
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.leftChild
else:#根节点删除
currentNode.replaceNodeData(currentNode.leftChild.key,
currentNode.leftChild.payload,
currentNode.leftChild.leftChild,
currentNode.leftChild.rightChild)
else:
if currentNode.isLeftChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.rightChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
currentNode.replaceNodeData(currentNode.rightChild.key,
currentNode.rightChild.payload,
currentNode.rightChild.leftChild,
currentNode.rightChild.rightChild)
elif currentNode.hasBothChildren():
succ = currentNode.findSuccessor()
succ.spliceOut()
currentNode.key = succ.key
currentNode.payload = succ.payload
def findSuccessor(self):
succ = None
if self.hasRightChild():
succ = self.rightChild.finMin()
else:#目前不会遇到
if self.parent:
if self.isLeftChild():
succ = self.parent
else:
self.parent.rightChild = None
succ = self.parent.findSuccessor()
self.parent.rightChild = self
return succ
def fimMin(self):
current = self
while current.hasLeftChild():
current = current.leftChild#直到左下角的节点
return current
def spliceOut(self):
if self.isLeaf():#摘出叶节点
if self.isLeftChild():
self.parent.leftChild = None
else:
self.parent.rightChild = None
elif self.hasAnyChildren():
if self.hasLeftChild():#目前不会遇到
if self.isLeftChild():
self.parent.leftChild = self.leftChild
else:
self.parent.rightChild = self.leftChild
self.leftChild.parent = self.parent
else:#摘出带右子节点的节点
if self.isLeftChild():
self.parent.leftChild = self.rightChild
else:
self.parent.rightChild = self.rightChild
self.rightChild.parent = self.parent
def _put(self,key,val,currentNode):
if key < currentNode.key:
if currentNode.hasLeftChild():
self._put(key,val,currentNode.leftChild)
else:
currentNode.leftChild = TreeNode(key,val,parent=currentNode)
self.updateBalance(currentNode.leftChild)#调整因子
else:
if currentNode.hasRightChild():
self._put(key,val,currentNode.rightChild)
else:
currentNode.rightChild = TreeNode(key,val,parent=currentNode)
self.updateBalance(currentNode.rightChild)#调整因子
def updateBalance(self, node):
if node.balanceFactor > 1 or node.balanceFactor < -1:
self.rebalance(node) # 重新平衡
return
if node.parent != None:
if node.isLeftChild():
node.parent.balanceFactor += 1
elif node.isRightChild():
node.parent.balanceFactor -= 1
if node.parent.balanceFactor != 0:
self.updateBalance(node.parent)#调整父节点因子
def rotateLeft(self, rotRoot):
newRoot = rotRoot.rightChild#新根节点是旧根节点的右子节点
rotRoot.rightChild = newRoot.leftChild#旧根节点的右子节点指向新根节点的左子节点
if newRoot.leftChild != None:
newRoot.leftChild.parent = rotRoot#如果新根节点有左子节点,那么需要把新根节点的左子节点挂到新左子节点(旧根节点)上
newRoot.parent = rotRoot.parent#新根节点的父节点调整为旧根节点的父节点
if rotRoot.isRoot():#判断如果旧根节点是树的根节点的话
self.root = newRoot#确立新的树根
else:
if rotRoot.isLeftChild():#如果旧节点是左子节点
rotRoot.parent.leftChild = newRoot
else:
rotRoot.parent.rightChild = newRoot
newRoot.leftChild = rotRoot
rotRoot.parent = newRoot
rotRoot.balanceFactor = rotRoot.balanceFactor + 1 - min(newRoot.balanceFactor, 0)#调整旧根节点的平衡因子
newRoot.balanceFactor = newRoot.balanceFactor + 1 + max(rotRoot.balanceFactor, 0)#调整新根节点的平衡因子
def rotateRight(self, rotRoot):
newRoot = rotRoot.leftChild
rotRoot.leftChild = newRoot.rightChild
if newRoot.rightChild != None:
newRoot.rightChild.parent = rotRoot
newRoot.parent = rotRoot.parent
if rotRoot.isRoot():
self.root = newRoot
else:
if rotRoot.isRightChild():
rotRoot.parent.rightChild = newRoot
else:
rotRoot.parent.leftChild = newRoot
newRoot.rightChild = rotRoot
rotRoot.parent = newRoot
rotRoot.balanceFactor = rotRoot.balanceFactor - 1 - max(newRoot.balanceFactor, 0)
newRoot.balanceFactor = newRoot.balanceFactor - 1 + min(rotRoot.balanceFactor, 0)
def rebalance(self, node):
if node.balanceFactor < 0:#右重需要左旋
if node.rightChild.balanceFactor > 0:
# Do an LR Rotation
self.rotateRight(node.rightChild)#右节点左重先右旋
self.rotateLeft(node)
else:
# single left
self.rotateLeft(node)#如果右子节点不是左重,则简单左旋
elif node.balanceFactor > 0:#左重需要右旋
if node.leftChild.balanceFactor < 0:
# Do an RL Rotation
self.rotateLeft(node.leftChild)#左子节点右重需左旋
self.rotateRight(node)
else:
# single right
self.rotateRight(node)#如果左子节点不右重,则简单右旋
有序表 | 散列表 | 二叉查找树(极端操作会退化到线性结构) | AVL树 | |
---|---|---|---|---|
put | O(n) | O(1)->O(n) | O( l o g 2 n log_2 n log2n)->O(n) | O( l o g 2 n log_2 n log2n) |
get | O( l o g 2 n log_2 n log2n) | O(1)->O(n) | O( l o g 2 n log_2 n log2n)->O(n) | O( l o g 2 n log_2 n log2n) |
in | O( l o g 2 n log_2 n log2n) | O(1)->O(n) | O( l o g 2 n log_2 n log2n)->O(n) | O( l o g 2 n log_2 n log2n) |
del | O(n) | O(1)->O(n) | O( l o g 2 n log_2 n log2n)->O(n) | O( l o g 2 n log_2 n log2n) |
一般来讲,对于内存和计算时间的要求不高时,用散列表较为合适,然后是AVL树
hashable定义
== 对应 eq
is对应id()
可哈希对象如果有相同的hash值,就是相等的==
不可哈希对象的相等,要枚举容器里的数据项逐个判断相等
id相同的对象,既相等(==),又同一(is):即同一个内存中
yield与return功能相似,当执行到yield时,会退出来,同时返回值
区别:return执行时,后面虽然不会执行,但下次再次调用时会从头开始
yield执行时,下次再次调用时,会从断点接着执行(yield处即为断点)
要求不高时,用散列表较为合适,然后是AVL树