一、树
1. 概念
之前讲了线性的数据结构:数组、列表、栈、队列,哈希表;接下来看树状结构,比如目录结构。
树是一种可以递归定义的数据结构,树有n个节点组成的集合:
- 如果n=0 ,是一颗空树;
- 如果n>0,那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树。
2. 实例:模拟文件系统
# 创建一个文件
class Node:
def __init__(self,name,type='dir'):
self.name = name
self.tyoe = type
self.children=[]
self.parent=None
# 将文件链式存储
class FileSystemTree:
def __init__(self):
self.root = Node('/')
self.now = self.root
def mkdir(self,name):
if name[-1] != '/':
name += '/'
node = Node(name)
self.now.children.append(node)
node.parent = self.now
def ls(self):
return self.now.children
def cd(self,name): # 切换目录
# 只支持向下走一层
if name[-1] != '/':
name+='/'
# 返回上一层
if name == '../':
self.now=self.now.parent
return
for child in self.now.children:
if child.name == name:
self.now = child
return
raise ValueError("invalid dir")
二、 二叉树的链式存储
将二叉树的节点定义为一个对象,节点之间通过类似 链表 的链接方式来连接。
class class BiTreeNode(object):
def __init__(self,data):
self.data = data
self.lchild = None # 左孩子
self.rchild = None # 右孩子
a=BiTreeNode('A')
b=BiTreeNode('B')
c=BiTreeNode('C')
d=BiTreeNode('D')
e=BiTreeNode('E')
f=BiTreeNode('F')
g=BiTreeNode('G')
e.lchild=a
e.rchild=g
a.rchild=c
c.lchild=b
c.rchild=d
g.rchild=f
root=e
三、二叉树的遍历
1. 前序遍历 E|ACBD|GF
2. 中序遍历 ABCD|E|GF
3. 后序遍历 BDCA|FG|E
4. 层次遍历 EAGCFBD ----使用到队列,访问出队元素的左右孩子。
# 前序遍历
def pre_order(root):
if root:
print(root.data,end=',')
pre_order(root.lchild)
pre_order(root.rchild)
# 中序遍历
def in_order(root):
if root:
in_order(root.lchild)
print(root.data,end=',')
in_order(root.rchild)
# 后序遍历
def post_order(root):
if root:
post_order(root.lchild)
post_order(root.rchild)
print(root.data,end=',')
pre_order(tree1)
# 层次遍历
from collections import deque
def level_order(root):
queue = deque()
queue.append(root)
while len(queue) > 0: # 只要队不空
node = queue.leftpop() # 父节点出队,它的左右孩子进队
print(node.data,end=',') # 输出父节点的data
if node.lchild: # 左孩子不空
queue.append(node.lchild)
if node.rchild:
queue.append(node.rchild)
例题:
如果给出前序遍历和中序遍历,怎么画出原本的二叉树,并给出后序遍历?
层次遍历不仅适用于二叉树,也适用于其他树。
# 层次遍历
from collections import deque
def level_order(root):
queue = deque() # 先创建一个队列
queue.append(root)
while len(queue)>0: # 重要队列不空
node = queue.popleft()
print(node.data,end=",")
if node.lchild: # 左子树不空
queue.qppend(node.lchild)
if node.rchild: # 右子树不空
queue.append(node.rchild)
四、 二叉搜索树(BST)---查询、插入(叶子节点下)、搜索
- 查询:最多查 二叉树的深度 次,大概时间复杂度 log(n)
- 插入:时间复杂度 log(n)
二叉搜索树的中序序列一定是升序的。
# 二叉树的实现
class BiTreeNode:
def __init__(self,data):
self.data = data
self.lchild = None
self.rchild = None
self.parent = None
# 二叉搜索树中 查询、插入、删除 操作
class BST:
def __init__(self,li=None):
self.root = None
if li:
for val in li:
self.insert_no_rec(val) # 使用非递归方式插入val
# 插入(递归和不递归)
def insert(self,node,val): # 递归插入
if not node:
node = BiTreeNode(val)
elif val < node.data:
node.lchild = self.insert(node.lchild,val)
node.lchild.parent = node
elif val > node.data:
node.rchild = self.insert(node.rchild,val)
node.rchild.parent = node
return node
def insert_no_rec(self,val):
p = self.root
if not p: #空树
self.root = BiTreeNode(val) # 更新root的值
return
while True: # 不是空树
if val < p.data:
if p.lchild: # 左孩子存在
p = p.lchild
else: # 到达叶子节点,即将执行插入操作
p.lchild = BiTreeNode(val) # 左孩子不存在,创建节点,双向链接
p.lchild.parent = p
return
elif val > p.data:
if p.rchild:
p = p.rchild
else:
p.rchild = BiTreeNode(val)
p.rchild.parent = p
return
else:
return
# 查询
def query(self,node,val):
if not node:
return None
elif node.data > val:
return query(node.lchild,val)
elif node.data < val:
return query(node.rchild,val)
else:
return node
def query_no_sec(self,val):
p = self.root
while p:
if p.data > val:
p = p.lchild
elif p.data < val:
p = p.rchild
else:
return p
return None
# 删除操作----三种情况:node是叶子节点、node只有一个孩子、node有两个孩子
def __delete_mode_1(self,node): # 1.删除节点node,node是叶子节点
if node.parent == None:
self.root = None
else:
if node == node.parent.lchild: # node是左孩子
node.parent.lchild = None
elif node == node.parent.rchild:
node.parent.rchild = None
def __delete_mode_21(self,node): # 2.1 删除节点node,node只有左孩子
if node.parent == None: # node是根节点
self.root = node.lchild
node.lchild.parent = None
elif node == node.parent.lchild: # node是左孩子
node.parent.lchild = node.lchild
node.lchild.parent = node.parent
else: # node == node.parent.rchild # node是右孩子
node.parent.rchild = node.lchild
node.lchild.parent = node.parent
def __delete_mode_22(self,node): # 2.2 删除节点node,node只有右孩子
if node.parent == None: # node是根节点
self.root = node.rchild
elif node == node.parent.lchild: # node是左孩子
node.parent.lchild = node.rchild
node.rchild.parent = node.parent
else: # node == node.parent.rchild # node是右孩子
node.parent.rchild = node.rchild
node.rchild.parent = node.parent
def delete(self,val):
if self.root: # 不是空树
node = self.query_no_sec(val)
if node == None: # 二叉搜索树中找不到node
return False
elif node.lchild == None and node.rchild == None: # 情况1:node是叶子节点
self.__delete_mode_1(node)
elif node.rchild == None: # 情况2: node只有左孩子
self.__delete_mode_21(val)
elif node.lchild ==None: # 情况2: node只有右孩子
self.__delete_mode_22(val)
# 3. node的左右孩子都有:用右子树中的最小值 替换node
else:
min_node = node.rchild
while min_node.lchild: # 右子树中沿着左子树一直往下:得到最小值
min_node = min_node.lchild
node.data = min_node.lchild # node.data被min_node的data替换
if min_node.rchild: # 最小值节点存在右子树(只有右子树):情形2.1
self.__delete_mode_22(min_node)
else: # 没有右子树:情形1
self.__delete_mode_1(min_node)
# 前序遍历
def pre_order(self,root):
if root: # 如果根节点不为空
print(root.data,end=',')
self.pre_order(root.lchild)
self.pre_order(root.rchild)
# 中序遍历
def in_order(self,root):
if root:
self.in_order(root.lchild)
print(root.data,end=',')
self.in_order(root.rchild)
# 后序遍历
def post_order(self,root):
if root:
self.post_order(root.lchild)
self.post_order(root.rchild)
print(root.data,end=',')
import random
list1=list(range(10))
random.shuffle(list1)
tree = BST(list1) #将这个列表插入(装换)二叉搜索树中
#插入
# tree.pre_order(tree.root)
# print("")
# tree.in_order(tree.root) # 二叉搜索树的中序遍历是升序
# print("")
# tree.post_order(tree.root)
#查询
# print(tree.query_no_sec(5))
#删除
# tree.in_order(tree.root)
# print("")
# tree.delete(3)
# tree.in_order(tree.root)
# print("")
# tree.delete(4)
# tree.in_order(tree.root)