树从顶部开始,由椭圆和箭头构成,并延伸到底部。树一个节点的所有子节点与其他节点的子节点无关。同时每一个叶子节点都是独一无二的。文件管理系统类似于一个树,html标签也类似于树。
树有一个根节点。除此以外,每个节点都与其唯一的父节点相连,从根节点到节点都有且仅有一条路径。若元素最多有两个子节点,称其为二叉树。
列表方式实现二叉树:
def binarytree(r):
return [r,[],[]]
# 左子树
def insertleft(root,newbranch):
t = root.pop(1)
if len(t) > 1:
root.insert(1,[newbranch,t,[]])
else:
root.insert(1,[newbranch,[],[]])
return root
# 右子树
def insertright(root,newbranch):
t = root.pop(2)
if len(t) > 1:
root.insert(2,[newbranch,[],t])
else:
root.insert(2,[newbranch,[],[]])
return root
def getrootval(root):
return root[0]
def setrootval(root,newroot):
root[0] = newroot
def getrootlefthild(root):
return root[1]
def getrootrighthild(root):
return root[2]
节点与引用表示法:
# 节点与引用创建树
class binarytree:
def __init__(self,rootobj):
self.key = rootobj
self.leftchild = None
self.rightchild = None
def insertleft(self,newnode):
if len(self.leftchild) == None:
self.leftchild = binarytree(newnode)
else:
t = binarytree(newnode)
t.leftchild = self.leftchild
self.leftchild = t
def insertright(self,newnode):
if len(self.rightchild) == None:
self.rightchild = binarytree(newnode)
else:
t = binarytree(newnode)
t.leftchild = self.rightchild
self.rightchild = t
def getleft(self):4
return self.leftchild
def getright(self):
return self.rightchild
def setrootval(self,obj):
self.key = obj
def getrootval(self):
return self.key
解析树
解析树可以用来对句子或某个表达式进行构造,以下是一个数学表达式的解析树。
解析树可以用来拆解完全括号表达式,在以下代码中,首先创建一个空树,碰上(就添加一个左节点,并来到子节点,碰上数字就给子节点值,而后回到父节点,碰上逻辑运算就添加给父节点,然后创建一个右节点并来到右节点,碰上数字就给右节点赋值并回到父节点,碰上)就返回父节点。为了追踪父节点,可以在前往子节点时将父节点,返回父节点时再取出父节点的值。
from pythonds.basic import Stack
from pythonds.trees import BinaryTree
def buildparsetree(fpexp):
s = Stack()
fplist = fpexp.split()
etree = BinaryTree('')
s.push(etree)
currenttree = etree
for i in fplist:
if i == "(":
currenttree.insertLeft("")
s.push(currenttree)
currenttree = currenttree.getLeftChild()
elif i in "0123456789":
currenttree.setRootVal(eval(i))
currenttree = s.pop()
elif i in "+-*/":
currenttree.setRootVal(i)
currenttree.insertRight("")
currenttree = currenttree.getRightChild()
elif i == ")":
currenttree = s.pop()
else:
raise ValueError("错误")
return etree
计算二叉解析树的递归函数。利用递归的方法,如果子节点存在就继续元算,否则就返回当前节点的值。function是四则运算的调用方法。
def evaluate(parsetree):
opers = {"+":operator.add,"-":operator.sub,"*":operator.mul,"/":operator.truediv}
leftc = parsetree.getleftChild()
rightc = parsetree.getrightChild()
if leftc and rightc:
fn = opers[parsetree.getRootVal()]
return fn(evaluate(leftc),evaluate(rightc))
else:
return parsetree.getRootVal()
树的遍历分为:前序遍历、中序遍历、后序遍历。前序遍历先访问根节点再访问左树,最后访问右树。中序遍历,先访问左子树,再访问根节点,最后访问右节点。后序遍历先访问左子树、再访问右子树,最后访问根节点。
# 前序遍历算法实现为外部函数
def preorder(tree):
if tree:
print(tree.getRootValue())
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
# 前序遍历算法实现为二叉树类
def preord(self):
print(self.key)
if self.leftChild:
self.left.preord()
if self.rightChild:
self.right.preord()
# 后续遍历函数
def postorder(tree):
if tree != None:
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
print(tree.getRootValue())
# 后序求值算法
def postorderevaluate(tree):
opers = {"+":operator.add,"-":operator.sub,"*":operator.mul,"/":operator.truediv}
res1 = None
res2 = None
if tree:
res1 = postorderevaluate(tree.getLeftChild())
res2 = postorderevaluate(tree.getRightChild)
if res1 and res2:
return opers[tree.getRootValue](res1,res2)
else:
return tree.getrootval()
# 中序便利函数
def inorder(tree):
if tree != None:
preorder(tree.getLeftChild())
print(tree.getRootValue())
preorder(tree.getRightChild())
def printexp(tree):
sval = " "
if tree:
sval = "(" + printexp(tree.getLeftChild())
sval = sval + str(tree.getrootval())
sval = printexp(tree.getRightChild()) + ")"
return sval
二叉堆的实现,二叉堆用于实现优先级队列,其实现时用一个列表作为表示。其变化有最小堆(最小堆在队首)和最大堆(最大元素在队首),它需要实现队的平衡,因此采用一个完全二叉树来实现平衡。在完全二叉树中,除了最底层,每一层节点都是满的。对于位置p节点来说,其左子节点为2p,右子节点为2p+1。在加入一个新元素的时候,要向上查找,如果父元素比他大就要向上交换。在移除最小元素的过程中,要将最末尾元素移动到首位,再向下比较。
class currentsize:
def __init__(self):
self.heaplist = [0]
self.currentsize = 0
def percup(self,i):
while i // 2 > 0 :
if self.heaplist[i // 2] > self.heaplist[i]:
temp = self.heaplist[i]
self.heaplist[i // 2] = self.heaplist[i]
self.heaplist[i] = temp
i = i // 2
def insert(self,x):
self.heaplist.append(x)
self.currentsize = self.currentsize +1
self.percup(self.currentsize)
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] <self.heaplist[i * 2 +1]:
return i * 2
else:
return i * 2 + 1
def delmin(self):
retval = self.heaplist[1]
self.heaplist[1] = self.heaplist[self.currentsize]
self.currentsize = self.currentsize - 1
self.heaplist.pop()
self.percdown(1)
return retval
def buildheap(self,alist):
i = len(alist) // 2
self.currentsize = len(alist)
self.heaplist = [0] + alist[:]
while (i>0):
self.percdown(i)
i -= 1