二叉树的Python实现
二叉树的定义
二叉树(Binary Tree)是n( n ≥ 0 n\ge 0 n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
图6-5-2就是一棵二叉树。而图6-2-1的树,因为D结点有三个子树,所以它不是二叉树。
二叉树的特点
二叉树的特点有:■ 每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。注意不是只有两棵子树,而是最多有。没有子树或者有一棵子树都是可以的。■ 左子树和右子树是有顺序的,次序不能任意颠倒。就像人是双手、双脚,但显然左手、左脚和右手、右脚是不一样的,右手戴左手套、右脚穿左鞋都会极其别扭和难受。■ 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。
二叉树具有五种基本形态:1.空二叉树。2.只有一个根结点。3.根结点只有左子树。4.根结点只有右子树。5.根结点既有左子树又有右子树。
斜树
所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树。
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
满二叉树的特点有:(1)叶子只能出现在最下一层。出现在其他层就不可能达成平衡。(2)非叶子结点的度一定是2。否则就是“缺胳膊少腿”了。(3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
完全二叉树的
对一棵具有n个结点的二叉树按层序编号,如果编号为i( 1 ≤ i ≤ n 1\le i\le n 1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树
完全二叉树的特点:(1)叶子结点只能出现在最下两层。(2)最下层的叶子一定集中在左部连续位置。(3)倒数二层,若有叶子结点,一定都在右部连续位置。(4)如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况。(5)同样结点数的二叉树,完全二叉树的深度最小。
满二叉树一定是一棵完全二叉树,但完全二叉树不一定是满的。
二叉树的性质
性质1:在二叉树的第 i i i层上至多有 2 i - 1 2^{i-1} 2i-1个结点( i ≥ 1 i\ge1 i≥1)。
性质2:深度为 k k k的二叉树至多有 2 k − 1 2^{k-1} 2k−1个结点( k ≥ 1 k \ge 1 k≥1)。
性质3:对任何一棵二叉树T,如果其终端结点数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1。
性质4:具有n个结点的完全二叉树的深度为 [ l o g 2 n ] + 1 [log_2n]+1 [log2n]+1( [ x ] [x] [x]表示不大于x的最大整数)。
性质5:如果对一棵有n个结点的完全二叉树(其深度为 [ l o g 2 n ] + 1 [log_2n]+1 [log2n]+1)的结点按层序编号(从第1层到第 [ l o g 2 n ] + 1 [log_2n]+1 [log2n]+1层,每层从左到右),对任一结点i( 1 ≤ i ≤ n 1\le i\le n 1≤i≤n)有:
1.如果 i = 1 i=1 i=1,则结点 i i i是二叉树的根,无双亲;如果i>1,则其双亲是结点 [ i / 2 ] [i/2] [i/2]。
2.如果 2 i > n 2i>n 2i>n,则结点 i i i无左孩子(结点 i i i为叶子结点);否则其左孩子是结点 2 i 2i 2i。
3.如果 2 i + 1 > n 2i+1>n 2i+1>n,则结点 i i i无右孩子;否则其右孩子是结点 2 i + 1 2i+1 2i+1。
二叉树的存储结构
二叉链表
二叉树每个结点最多有两个孩子,所以为它设计一个数据域和两个指针域是比较自然的想法,我们称这样的链表叫做二叉链表。
lchild | data | rchild |
---|
其中data是数据域,lchild和rchild都是指针域,分别存放指向左孩子和右孩子的指针。
由于Python种没有指针,所以用类实现比较方便。
class Node():
def __init__(self, data = None, lchild = None, rlchild = None):
self.data = data
self.lchild = lchild
self.rchild = rlchild
self.ltag = 0
self.rtag = 0
节点添加(仅限完全二叉树、非完全二叉树未实现)
通过另外一个类实现节点数据添加
class BiTree():
out = []
def __init__(self):
self.root = None
def isEmpty(self):
return self.root == None
def AddNode(self,data):
'''
通过队列的方式添加节点元素
类似层序遍历
:param data:
:return:
'''
node = Node(data)
# 如果树根节点为空
if self.root == None:
self.root = node
return
queue = [self.root]
while queue: #当队列中没有属性时退出循环
cur = queue.pop(0) #参数0删除最前面一个元素弹出(没有参数默认为栈)
#先左后右 左边满了右边才能添加
if cur.lchild == None:
cur.lchild = node
return
else:
queue.append(cur.lchild) #左节点有空位就把左节点属性拿出来放到队列中
if cur.rchild == None:
cur.rchild = node
return
else:
queue.append(cur.rchild) #左节点有空位就把左节点属性拿出来放到队列中
最终结果会形成类似链表的结构
遍历二叉树
二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。
前序遍历
规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
递归实现
二叉树的定义是用递归的方式,所以,实现遍历算法也可以采用递归,而且极其简洁明了。
def PreOrderTraverse(self,node = True,flag = False):
'''
先序遍历(递归实现)
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
print(node.data,end = " ")
self.out.append(node.data)
self.PreOrderTraverse(node.lchild)
self.PreOrderTraverse(node.rchild)
非递归实现
能用递归,当然能用栈来实现。
def PreOrderTraverseWithoutRecursion(self):
'''
前序遍历(非递归)栈实现
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
while stack or cur != None :
#遍历左子树,节点存入栈中,以后需要借助栈保存的节点进入右子树
while cur != None:
# print(cur.data)
output.append(cur.data)
stack.append(cur)
cur = cur.lchild
#当cur为None时,说明根和左子树都遍历完了,借助栈保存的节点进入右子树
if stack:
cur = stack.pop()
cur = cur.rchild
# 测试栈内元素是否正确
# for i in stack:
# print(i.data,end=" ")
# print()
return output
(下图仅供参考 上案例仅限完全二叉树)
中序遍历
规则是若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。
递归实现
def InOrderTraverse(self,node = True,flag = False):
'''
中序遍历(递归实现)
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.InOrderTraverse(node.lchild)
print(node.data, end=" ")
self.InOrderTraverse(node.rchild)
非递归实现
def InOrderTraverseWithoutRecursion(self):
'''
中序遍历(非递归)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
while stack or cur != None :
#遍历到左子树最下边,边遍历边保存根节点到栈中
while cur != None:
# print(cur.data)
stack.append(cur)
cur = cur.lchild
if stack:
cur = stack.pop()
output.append(cur.data)
#进入右子树,开始新的一轮左子树遍历
cur = cur.rchild
# 测试栈内元素是否正确
# for i in stack:
# print(i.data,end=" ")
# print()
return output
(下图仅供参考 上案例仅限完全二叉树)
后序遍历
规则是若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。
递归实现
def PostOrderTraverse(self,node = True,flag = False):
'''
后序遍历
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.PostOrderTraverse(node.lchild)
self.PostOrderTraverse(node.rchild)
print(node.data, end=" ")
非递归实现
def PostOrderTraverseWithoutRecursion(self):
'''
后续遍历(非递归)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
pcur = None
# 先把标志cur移动到左子树最下边
while cur != None:
# print(cur.data)
stack.append(cur)
cur = cur.lchild
while stack:
# 走到这里,cur都是空,并已经遍历到左子树底端
cur = stack.pop()
#一个根节点被访问的前提是:无右子树或右子树已被访问过
if cur.rchild == None or cur.rchild == pcur:
output.append(cur.data)
#修改最近被访问的节点
pcur = cur
else:
#根节点再次入栈
stack.append(cur)
#进入右子树,且可肯定右子树一定不为空
cur = cur.rchild
while cur:
stack.append(cur)
cur = cur.lchild
return output
层序遍历
规则是若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。
def LevelOrderTraverse(self,flag = False):
'''
层序遍历(队列实现)
:param flag: 有待扩展(如非完全二叉树)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
queue = [self.root]
while queue:
cur = queue.pop(0)
output.append(cur.data)
#先左后右
if cur.lchild:
queue.append(cur.lchild)
if cur.rchild:
queue.append(cur.rchild)
return output
(下图仅供参考 上案例仅限完全二叉树)
线索二叉树
指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树(Threaded Binary Tree)。
其实线索二叉树,等于是把一棵二叉树转变成了一个双向链表,这样对我们的插入删除结点、查找某个结点都带来了方便。所以我们对二叉树以某种次序遍历使其变为线索二叉树的过程称做是线索化。
lchild | Itag | data | rtag | rchild |
---|
其中:■ ltag为0时指向该结点的左孩子,为1时指向该结点的前驱。■ rtag为0时指向该结点的右孩子,为1时指向该结点的后继。■ 因此对于图6-10-1的二叉链表图可以修改为图6-10-5的样子。
由此二叉树的线索存储结构定义代码如下:
class ThBiTreeNode():
def __init__(self, data = None, lchild = None, rlchild = None):
self.data = data
self.lchild = lchild
self.rchild = rlchild
self.ltag = 0
self.rtag = 0
添加节点
class ThBiTree(BiTree):
def __init__(self):
self.root = None
self.pre = None # 为实现线索化,需要创建给指向当前结点的前驱结点指针
def update(self):
self.pre = None
self.out = []
def CreatTree(self,List):
'''
#通过循环迅速创建树
:param List: 列表存储树的结构
:return: None
'''
BiTree.CreatTree(self, List)
self.pre = None
线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继的信息只有在遍历该二叉树时才能得到,所以线索化的过程就是在遍历的过程中修改空指针的过程。
中序线索化
def ThreadedInOrder(self, node = True):
"""
中序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
# 先线索化左子树
self.ThreadedInOrder(node.lchild)
# 线索化当前结点
# 处理当前结点的前驱结点
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
# 线索化右子树
self.ThreadedInOrder(node.rchild)
中序线索化遍历
def ThreadedInOrderTraverse(self, node = True):
"""
中序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
#先线索化才能遍历
self.ThreadedInOrder()
temp_node = node
while temp_node:
# 循环的找到ltag=1的结点
# 后面随着遍历而变化,因为当ltag=1时,说明该结点是按照线索化处理后的有效结点
while temp_node.ltag == 0: # 从根结点开始向左找,找到中序序列的第一个节点板
temp_node = temp_node.lchild
# 打印当前这个结点
print(temp_node.data, end=" ")
# 如果当前结点的右指针指向的是后继结点,就一直输出
while temp_node.rtag == 1:
# 获取到当前结点的后继结点
temp_node = temp_node.rchild
print(temp_node.data, end=" ")
# 如果不等于1了,就替换这个遍历的结点 p进至右子树根
temp_node = temp_node.rchild
前序线索化
def ThreadedPreOrder(self, node = True):
"""
前序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
if node.ltag == 0:
# 先线索化左子树
self.ThreadedPreOrder(node.lchild)
if node.rtag == 0:
# 线索化右子树
self.ThreadedPreOrder(node.rchild)
前序线索化遍历
def ThreadedPreOrderTraverse(self, node = True):
"""
前序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.ThreadedPreOrder()
temp_node = node
while temp_node:
while temp_node.ltag == 0:
# 打印当前这个结点
print(temp_node.data, end=" ")
temp_node = temp_node.lchild
# 如果当前结点的右指针指向的是后继结点,就一直输出
while temp_node.rtag == 1:
print(temp_node.data, end=" ")
# 获取到当前结点的后继结点
temp_node = temp_node.rchild
print(temp_node.data, end=" ")
if temp_node.ltag == 0:
temp_node = temp_node.lchild
else:
# p进至右子树根
temp_node = temp_node.rchild
后续线索化
def ThreadedPostOrder(self, node = True):
"""
后序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
# 先线索化左子树
self.ThreadedPostOrder(node.lchild)
# 线索化右子树
self.ThreadedPostOrder(node.rchild)
# 处理当前结点的前驱结点
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
后续线索化遍历
def ThreadedPostOrderTraverse(self, node=True):
"""
后序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.ThreadedPostOrder()
temp_node = node
stack = []
while temp_node:
#先遍历右子树
while temp_node.rtag == 0:
stack.append(temp_node)
temp_node = temp_node.rchild
#右子树没有后继的话再遍历左子树
stack.append(temp_node)
temp_node = temp_node.lchild
#栈先入后出 左子树数据先打印,在打印右子树
while stack:
temp_node = stack.pop()
print(temp_node.data, end=" ")
代码汇总
class Node():
def __init__(self, data = None, lchild = None, rlchild = None):
self.data = data
self.lchild = lchild
self.rchild = rlchild
self.ltag = 0
self.rtag = 0
class BiTree():
out = []
def __init__(self):
self.root = None
def isEmpty(self):
return self.root == None
def AddNode(self,data):
'''
通过队列的方式添加节点元素
类似层序遍历
:param data:
:return:
'''
node = Node(data)
# 如果树根节点为空
if self.root == None:
self.root = node
return
queue = [self.root]
while queue: #当队列中没有属性时退出循环
cur = queue.pop(0) #参数0删除最前面一个元素弹出(没有参数默认为栈)
#先左后右 左边满了右边才能添加
if cur.lchild == None:
cur.lchild = node
return
else:
queue.append(cur.lchild) #左节点有空位就把左节点属性拿出来放到队列中
if cur.rchild == None:
cur.rchild = node
return
else:
queue.append(cur.rchild) #左节点有空位就把左节点属性拿出来放到队列中
def PreOrderTraverse(self,node = True,flag = False):
'''
先序遍历(递归实现)
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
print(node.data,end = " ")
self.out.append(node.data)
self.PreOrderTraverse(node.lchild)
self.PreOrderTraverse(node.rchild)
def InOrderTraverse(self,node = True,flag = False):
'''
中序遍历(递归实现)
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.InOrderTraverse(node.lchild)
print(node.data, end=" ")
self.InOrderTraverse(node.rchild)
def PostOrderTraverse(self,node = True,flag = False):
'''
后序遍历
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.PostOrderTraverse(node.lchild)
self.PostOrderTraverse(node.rchild)
print(node.data, end=" ")
def LevelOrderTraverse(self,flag = False):
'''
层序遍历(队列实现)
:param flag: 有待扩展(如非完全二叉树)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
queue = [self.root]
while queue:
cur = queue.pop(0)
output.append(cur.data)
#先左后右
if cur.lchild:
queue.append(cur.lchild)
if cur.rchild:
queue.append(cur.rchild)
return output
def PreOrderTraverseWithoutRecursion(self):
'''
前序遍历(非递归)栈实现
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
while stack or cur != None :
#遍历左子树,节点存入栈中,以后需要借助栈保存的节点进入右子树
while cur != None:
# print(cur.data)
output.append(cur.data)
stack.append(cur)
cur = cur.lchild
#当cur为None时,说明根和左子树都遍历完了,借助栈保存的节点进入右子树
if stack:
cur = stack.pop()
cur = cur.rchild
# 测试栈内元素是否正确
# for i in stack:
# print(i.data,end=" ")
# print()
return output
def InOrderTraverseWithoutRecursion(self):
'''
中序遍历(非递归)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
while stack or cur != None :
#遍历到左子树最下边,边遍历边保存根节点到栈中
while cur != None:
# print(cur.data)
stack.append(cur)
cur = cur.lchild
if stack:
cur = stack.pop()
output.append(cur.data)
#进入右子树,开始新的一轮左子树遍历
cur = cur.rchild
# 测试栈内元素是否正确
# for i in stack:
# print(i.data,end=" ")
# print()
return output
def PostOrderTraverseWithoutRecursion(self):
'''
后续遍历(非递归)
:return: output 遍历后的序列
'''
if self.isEmpty() == True:
print("The Tree is empty.")
return
output = []
stack = []
cur = self.root
pcur = None
# 先把标志cur移动到左子树最下边
while cur != None:
# print(cur.data)
stack.append(cur)
cur = cur.lchild
while stack:
# 走到这里,cur都是空,并已经遍历到左子树底端
cur = stack.pop()
#一个根节点被访问的前提是:无右子树或右子树已被访问过
if cur.rchild == None or cur.rchild == pcur:
output.append(cur.data)
#修改最近被访问的节点
pcur = cur
else:
#根节点再次入栈
stack.append(cur)
#进入右子树,且可肯定右子树一定不为空
cur = cur.rchild
while cur:
stack.append(cur)
cur = cur.lchild
return output
#以下内容仅仅自娱自乐
def CreatTree(self,List):
'''
#通过循环迅速创建树
:param List: 列表存储树的结构
:return: None
'''
self.root = None
for i in List:
self.AddNode(i)
def update(self):
'''
一些属性的更新
:return:
'''
self.out = []
def GetNodeList(self,node = True):
'''
先序遍历获取节点序列
:param node: 递归节点赋值接口(默认不用给值)
:param flag: 有待扩展(如非完全二叉树)
:return: None
'''
# 如果节点为空
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
#self.out在这里充当类中全局变量的作用
print(node.data,end = " ")
self.out.append(node.data)
self.GetNodeList(node.lchild)
self.GetNodeList(node.rchild)
return self.out
def BreakTree(self,node):
'''
将二叉树T拆分为根结点元素element,左子树L和右子树R三部分*/
#由于python没有指针所以这个,最简单的方法是通过遍历获取左子树、右子树 这个一个比较蠢的做法(实力受限)
:return:
'''
if node == None:
print("The Tree is empty.")
return
print(node.data)
out1 = BiTree()
out1.AddNode(node.data)
out1.update()
out = out1.GetNodeList(node.lchild)
out1.update()
out2 = BiTree()
out2.CreatTree(out)
print(out2.root.data)
x.update()
out = out1.GetNodeList(node.rchild)
out3 = BiTree()
out3.CreatTree(out)
return out1, out2, out3
def size(self, node = True):
'''
获取二叉树的节点数目
:param node:递归节点赋值接口(默认不用给值)
:return:size
'''
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return 0
lsize = self.size(node.lchild)
rsize = self.size(node.rchild)
return lsize + rsize + 1
def height(self,node = True):
'''
获取二叉树的高度 = ⌊log2n⌋+1
:param node:
:return:height
'''
import math
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return 0
size = self.size()
return math.floor(math.log2(size))+1
class ThBiTreeNode():
def __init__(self, data = None, lchild = None, rlchild = None):
self.data = data
self.lchild = lchild
self.rchild = rlchild
self.ltag = 0
self.rtag = 0
class ThBiTree(BiTree):
def __init__(self):
self.root = None
self.pre = None # 为实现线索化,需要创建给指向当前结点的前驱结点指针
def ThreadedInOrder(self, node = True):
"""
中序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
# 先线索化左子树
self.ThreadedInOrder(node.lchild)
# 线索化当前结点
# 处理当前结点的前驱结点
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
# 线索化右子树
self.ThreadedInOrder(node.rchild)
def ThreadedInOrderTraverse(self, node = True):
"""
中序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
#先线索化才能遍历
self.ThreadedInOrder()
temp_node = node
while temp_node:
# 循环的找到ltag=1的结点
# 后面随着遍历而变化,因为当ltag=1时,说明该结点是按照线索化处理后的有效结点
while temp_node.ltag == 0: # 从根结点开始向左找,找到中序序列的第一个节点板
temp_node = temp_node.lchild
# 打印当前这个结点
print(temp_node.data, end=" ")
# 如果当前结点的右指针指向的是后继结点,就一直输出
while temp_node.rtag == 1:
# 获取到当前结点的后继结点
temp_node = temp_node.rchild
print(temp_node.data, end=" ")
# 如果不等于1了,就替换这个遍历的结点 p进至右子树根
temp_node = temp_node.rchild
# 二叉树进行前序线索化的方法
def ThreadedPreOrder(self, node = True):
"""
前序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
if node.ltag == 0:
# 先线索化左子树
self.ThreadedPreOrder(node.lchild)
if node.rtag == 0:
# 线索化右子树
self.ThreadedPreOrder(node.rchild)
def ThreadedPreOrderTraverse(self, node = True):
"""
前序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.ThreadedPreOrder()
temp_node = node
while temp_node:
while temp_node.ltag == 0:
# 打印当前这个结点
print(temp_node.data, end=" ")
temp_node = temp_node.lchild
# 如果当前结点的右指针指向的是后继结点,就一直输出
while temp_node.rtag == 1:
print(temp_node.data, end=" ")
# 获取到当前结点的后继结点
temp_node = temp_node.rchild
print(temp_node.data, end=" ")
if temp_node.ltag == 0:
temp_node = temp_node.lchild
else:
# p进至右子树根
temp_node = temp_node.rchild
# 二叉树进行前序线索化的方法
def ThreadedPostOrder(self, node = True):
"""
后序线索化
重新设定lchild与rchild,rtag与ltag
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
# 先线索化左子树
self.ThreadedPostOrder(node.lchild)
# 线索化右子树
self.ThreadedPostOrder(node.rchild)
# 处理当前结点的前驱结点
if node.lchild == None: # 如果当前结点左子结点为空
node.lchild = self.pre # 让当前结点的左指针指向前驱结点
node.ltag = 1 # 修改当前结点的左指针类型 为 前驱结点
# 处理当前结点的后继结点
if self.pre and self.pre.rchild == None:
self.pre.rchild = node # 让前驱结点的右指针指向当前结点
self.pre.rtag = 1 # 修改前驱结点的右指针类型
self.pre = node # 每处理一个结点后,让当前结点是下一个结点的前驱结点
def ThreadedPostOrderTraverse(self, node=True):
"""
后序线索化遍历
:param node: 节点
:return: None
"""
if node == True:#该语句仅仅是为了避免root输入跟节点
node = self.root
if node == None:
return
self.ThreadedPostOrder()
temp_node = node
stack = []
while temp_node:
#先遍历右子树
while temp_node.rtag == 0:
stack.append(temp_node)
temp_node = temp_node.rchild
#右子树没有后继的话再遍历左子树
stack.append(temp_node)
temp_node = temp_node.lchild
#栈先入后出 左子树数据先打印,在打印右子树
while stack:
temp_node = stack.pop()
print(temp_node.data, end=" ")
def update(self):
self.pre = None
self.out = []
def CreatTree(self,List):
'''
#通过循环迅速创建树
:param List: 列表存储树的结构
:return: None
'''
BiTree.CreatTree(self, List)
self.pre = None
if __name__ =='__main__':
x = BiTree()
x.AddNode(1)
x.AddNode(2)
x.AddNode(3)
x.AddNode(4)
x.AddNode(5)
x.AddNode(6)
x.AddNode(7)
x.AddNode(8)
x.AddNode(9)
x.AddNode(10)
print('层序遍历')
out = x.LevelOrderTraverse()
print(out)
print('前序遍历')
x.PreOrderTraverse()
print()
print('前序遍历非递归')
out = x.PreOrderTraverseWithoutRecursion()
print(out)
print('中序遍历')
x.InOrderTraverse()
print()
print('中序遍历非递归')
out = x.InOrderTraverseWithoutRecursion()
print(out)
print('后序遍历')
x.PostOrderTraverse()
print()
print('后序遍历非递归')
out = x.PostOrderTraverseWithoutRecursion()
print(out)
L = [3,4,1,5,2,7,10,37,15,34,2,1,3]
x = BiTree()
for i in L:
x.AddNode(i)
out = x.LevelOrderTraverse()
print(out)
x.PreOrderTraverse()
print()
out = x.PreOrderTraverseWithoutRecursion()
print(out)
print()
x.InOrderTraverse()
print()
out = x.InOrderTraverseWithoutRecursion()
print(out)
print()
x.PostOrderTraverse()
print()
out = x.PostOrderTraverseWithoutRecursion()
print(out)
a,b,c = x.BreakTree(x.root.lchild)
c.PreOrderTraverse()
print()
b.PreOrderTraverse()
print()
out = x.size()
print('x.size={0}\n'.format(out))
out = x.height()
print('x.height={0}\n'.format(out))
L = [3,4,1,5,2,7,10,37,15,34,2,1,3]
L = [1,2,3,4,5,6,7,8,9,10]
x = ThBiTree()
x.CreatTree(L)
print()
x.PreOrderTraverse()
print()
x.ThreadedPreOrderTraverse()
print()
x.CreatTree(L)
print()
x.InOrderTraverse()
print()
x.ThreadedInOrderTraverse()
print()
x.CreatTree(L)
print()
x.PostOrderTraverse()
print()
x.ThreadedPostOrderTraverse()
print()
x = BiTree()
x.AddNode('A')
x.AddNode('B')
x.AddNode('C')
x.AddNode('D')
x.AddNode('E')
x.AddNode('F')
x.AddNode('G')
x.AddNode('H')
x.AddNode('I')
print('层序遍历')
out = x.LevelOrderTraverse()
print(out)
print('前序遍历')
x.PreOrderTraverse()
print()
print('前序遍历非递归')
out = x.PreOrderTraverseWithoutRecursion()
print(out)
print('中序遍历')
x.InOrderTraverse()
print()
print('中序遍历非递归')
out = x.InOrderTraverseWithoutRecursion()
print(out)
print('后序遍历')
x.PostOrderTraverse()
print()
print('后序遍历非递归')
out = x.PostOrderTraverseWithoutRecursion()
print(out)