Python二叉树详解笔记
目录
二叉树数据结构
简介
为何选择树
树的主要应用包括:
二叉树的类型
满二叉树(Full binary tree)
完全二叉树(Complete binary tree)
完美二叉树(Perfect binary tree)
平衡二叉树(Balanced Binary Tree)
退化(或病态)树(Degenerate (or pathological) tree)
二叉排序树
代码实现
以class类创建树的单个节点
创建一个简单的树
创建二叉排序树(递归插入方法)
树遍历(前序,中序和后序)
前序遍历
中序遍历
后序遍历
删除树
二叉树数据结构
简介
元素最多包含2个子元素的树称为二叉树。由于二叉树中的每个元素只能有2个子元素,因此我们通常将它们命名为左右子元素。
二叉树节点包含以下部分。
- 数据
- 指向左子节点的指针
- 指向右子节点的指针
树:与阵列,链接列表,堆栈和队列(线性数据结构)不同,树是分层数据结构。
树 词汇表:最顶层的节点称为树的根。直接位于元素下的元素称为子元素。直接在某个东西上方的元素称为其父元素。例如,'a'是'f'的子元素,'f'是'a'的父元素。最后,没有孩子的元素被称为叶子。
tree ---- j <-- root / f k / a h z <-- leaves
为何选择树
1. 使用树的一个原因可能是因为您希望存储自然形成层次结构的信息。例如,计算机上的文件系统:
file system ----------- / <-- root / ... home / ugrad course / / | ... cs101 cs112 cs113
2.树(具有一些排序,例如BST)提供适度的访问/搜索(比链接列表更快并且比数组慢)。 3.树提供适度的插入/删除(比阵列更快,比无序链接列表慢)。 4.与链接列表类似,与阵列不同,当节点使用指针链接时,树没有节点数量的上限。
树的主要应用包括:
1. 处理分层数据。 2. 使信息易于搜索(参见树遍历)。 3. 处理已排序的数据列表。 4. 作为合成视觉效果的数字图像的工作流程。 5. 路由器算法 6. 多阶段决策的形式(见商业象棋)。
二叉树的类型
满二叉树(Full binary tree)
如果每个节点有0或2个子节点,则二叉树已满。
以下是满二叉树的示例。我们还可以说满二叉树是一个其中除了叶子之外的所有节点都有两个子节点的二叉树。
18 / 15 30 / / 40 50 100 40 18 / 15 20 / 40 50 / 30 50 18 / 40 30 / 100 40
在满二叉树文件中,叶节点数是内部节点数加1,内部节点是有子节点的的节点 L = I + 1 其中L =叶节点数,I =内部节点数
完全二叉树(Complete binary tree)
完全二叉树,所有层都被完全填充,除了可能是最后一级,最后一级是尽可能保留所有键
以下是完整二叉树的示例
18 / 15 30 / / 40 50 100 40 18 / 15 30 / / 40 50 100 40 / / 8 7 9
完美二叉树(Perfect binary tree)
二叉树是完美的二叉树,其中所有内部节点都有两个子节点,所有叶子都在同一级别。 以下是完美二叉树的例子
18 / 15 30 / / 40 50 100 40 18 / 15 30
高度为h的完美二叉树(其中高度是从根到叶的路径上的节点数)具有2^(h - 1)个节点。
平衡二叉树(Balanced Binary Tree)
如果树的高度为O(Log n),则二叉树是平衡的,其中n是节点数。例如,AVL树通过确保左右子树高度之间的差异最大为1来维持O(Log n)高度。红黑树通过确保黑色节点的数量保持O(Log n)高度每个根到叶子路径是相同的,没有相邻的红色节点。平衡二进制搜索树在性能方面是明智的,因为它们为搜索,插入和删除提供了O(log n)时间。
退化(或病态)树(Degenerate (or pathological) tree)
每个内部节点都有一个子树。这些树在性能方面与链表相同。
10 / 20 30 40
二叉排序树
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。
代码实现
以class类创建树的单个节点
使用python的class类表示单个节点,节点中应包含当前节点的值、左节点指针、右节点指针
class Node:
def __init__(self, data=None):
self.val = data # 节点值指针
self.right = None # 右节点指针
self.left = None # 左节点指针
创建一个简单的树
先创建跟节点,然后依次分配左右子节点
if __name__ == '__main__':
tree = Node(1)
''' 以下是上述声明后的树
1
/
None None'''
tree.left = Node(2)
tree.right = Node(3)
''' 2和3成为1的左右子树
1
/
2 3
/ /
None None None None'''
tree.left.left = Node(4)
''' 4成为2的左子树
1
/
2 3
/ /
4 None None None
/
None None'''
创建二叉排序树(递归插入方法)
步骤: 1、若根结点的值等于查找的值,成功。 2、否则,若小于根结点的值,递归查左子树。 3、若大于根结点的值,递归查右子树。 4、若子树为空,查找不成功。
class Node:
def __init__(self, data=None):
self.value = data # 节点值指针
self.right = None # 右节点指针
self.left = None # 左节点指针
def insert(self, data):
if self.value: # 判断是否存在根节点
if data < self.value: # 若小于当前根节点,则放左边
if self.left is None: # 若左边子树是空的,则添加到后面
self.left = Node(data) # 新建节点后添加入末尾
else: # 否则递归调用,直到到达末尾
self.left.insert(data)
elif data > self.value: # 若大于当前跟节点,则放右边
if self.right is None: # 若右边子树是空的,则添加到后面
self.right = Node(data) # 新建节点后添加入末尾
else: # 否则递归调用,直到到达末尾
self.right.insert(data)
else:
self.value = data # 不存在根节点,就将值设置为根节点
树遍历(前序,中序和后序)
前序遍历
算法(树) 1.访问root。 2.遍历左子树,即调用Preorder(左子树) 3.遍历右子树,即调用Preorder(右子树)
ABDHIEJCFKG
class Node:
def preorderTraversal(self, root):
res = []
if root:
res.append(root.value)
res += self.preorderTraversal(root.left)
res += self.preorderTraversal(root.right)
return res
if __name__ == '__main__':
tree = Node()
tree.insert(2)
tree.insert(3)
tree.insert(5)
tree.insert(1)
tree.insert(7)
res = tree.preorderTraversal(tree)
print(res)
# Output:
# [2, 1, 3, 5, 7]
中序遍历
算法顺序(树) 1.遍历左子树,即调用Inorder(左子树) 2.访问root。 3.遍历右子树,即调用Inorder(右子树)
HDIBEJAFKCG
class Node:
def inorderTraversal(self, root):
res = []
if root:
res += self.inorderTraversal(root.left)
res.append(root.value)
res += self.inorderTraversal(root.right)
return res
if __name__ == '__main__':
tree = Node()
tree.insert(2)
tree.insert(3)
tree.insert(5)
tree.insert(1)
tree.insert(7)
res = tree.inorderTraversal(tree)
print(res)
# Output:
# [1, 2, 3, 5, 7]
后序遍历
算法(树) 1.遍历左子树,即调用Postorder(左子树) 2.遍历右子树,即调用Postorder(右子树) 3.访问root。
HIDJEBKFGCA
class Node:
def postorderTraversal(self, root):
res = []
if root:
res += self.postorderTraversal(root.left)
res += self.postorderTraversal(root.right)
res.append(root.value)
return res
if __name__ == '__main__':
tree = Node()
tree.insert(2)
tree.insert(3)
tree.insert(5)
tree.insert(1)
tree.insert(7)
res = tree.postorderTraversal(tree)
print(res)
# Output:
# [1, 7, 5, 3, 2]
删除树
要删除树,我们必须遍历树的所有节点并逐个删除它们。所以我们应该使用哪种遍历? - 前序或中序或后序?答案很简单 -> 后序,因为在删除父节点之前,我们应该首先删除它的子节点。删除了树,还要将root更改为NULL
对于以下树节点,按顺序删除 - 4,5,2,3,1
def _deleteTree(root):
if root:
_deleteTree(root.left) # 首先删除两个子树
_deleteTree(root.right) # 首先删除两个子树
print(" 删除节点:", root.value)
root = None # 然后删除节点
def deleteTree(root):
_deleteTree(root) # 删除树
root = None # 并将根设置为NULL
if __name__ == '__main__':
tree = Node()
tree.insert(2)
tree.insert(3)
tree.insert(5)
tree.insert(1)
tree.insert(7)
res = tree.postorderTraversal(tree)
print(res)
deleteTree(tree)
# Output:
# [1, 7, 5, 3, 2]
# 删除节点: 1
# 删除节点: 7
# 删除节点: 5
# 删除节点: 3
# 删除节点: 2
未完待续...
欢迎关注↓↓↓
- 微信公众号:xfxuezhang
- 【干货】用于机器学习的线性代数速查表
- 使用机器学习预测天气(第一部分)
- linux 常用指令
- LCS 算法:Javascript 最长公共子序列
- 短网址(short URL)系统的原理及其实现
- 设计和实现一款轻量级的爬虫框架
- JavaScript实现模糊推荐的input框(类似搜索框)
- hadoop streaming编程小demo(python版)
- 一个scrapy框架的爬虫(爬取京东图书)
- mongodb生产环境(副本集模式)集群搭建配置
- ELK日志收集分析系统配置
- 【学术】如何在15分钟内建立一个深度学习模型?
- Elasticsearch(GEO)空间检索查询
- java spark-streaming接收TCP/Kafka数据
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux nl命令的使用方法
- Linux gcc命令的具体使用
- Linux dirname命令的具体使用
- Linux 相对路径和绝对路径的使用
- Linux basename命令的使用方法
- 在Ubuntu上搭建一个基于webrtc的多人视频聊天服务实例代码详解
- linux中权限管理命令详解(chmod/chown/chgrp/unmask)
- linux下用time(NULL)函数和localtime()获取当前时间的方法
- linux防火墙状态查看的方法实例
- 详解在linxu下Svn一键安装shell脚本
- Linux中screen命令及使用方法
- Linux中安装Composer的步骤分享
- Linux md5sum命令的使用方法
- linux文件管理命令实例分析【显示、查看、统计等】
- linux用户和组命令实例分析【切换、添加用户、权限控制等】