数据结构-非线性结构-树形结构:有序树 ---->二叉树【动态数据结构】

2024-09-02 03:18

本文主要是介绍数据结构-非线性结构-树形结构:有序树 ---->二叉树【动态数据结构】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)

在这里插入图片描述

一、二叉树的特性

  • 性质1: 在二叉树的第i层上至多有2(i-1)个结点(i>0)
  • 性质2: 深度为k的二叉树至多有2(k-1)个结点(k>0)
  • 性质3: 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
  • 性质4:具有n个结点的完全二叉树的深度必为 log2(n+1)
  • 性质5:对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1 时为根,除外)

二、二叉树的种类

1、完全二叉树

完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树,其中满二叉树的定义是所有叶节点都在最底层的完全二叉树。

在这里插入图片描述

2、满二叉树

满二叉树:除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树,每一层都挂满了节点。

在这里插入图片描述

3、平衡二叉树

平衡二叉树(AVL树):当且仅当任何节点的两棵子树的高度差不大于1的二叉树

在这里插入图片描述

4、搜索/排序二叉树

排序二叉树(二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树),排序二叉树包含空树。

排序二叉树(BST)的要求:

  1. 若左子树不空,则左子树上所有节点的值均小于它的根节点的值
  2. 若右子树不空,则右子树上所有节点的值均大于它的根节点的值
  3. 左、右子树也分别为二叉搜索/排序树
    在这里插入图片描述

5、二分搜索树、AVL树(平衡二叉树)、红黑树(准平衡二叉树) 性能对比

在这里插入图片描述

三、二叉树的存储

1、顺序存储

顺序存储:将数据结构存储在固定的数组中,虽然在遍历速度上有一定的优势,但因所占空间比较大,是非主流二叉树
存储方式.二叉树通常以链式存储。

在这里插入图片描述

2、链式存储

链式存储:由于对节点的个数无法掌握,常见树的存储表示都转换成二叉树进行处理,子节点个数最多为2。

在这里插入图片描述

四、二叉树-代码实现

class Node(object):"""二叉树节点"""def __init__(self, item):self.elem = itemself.lchild = Noneself.rchild = Noneclass BinaryTree(object):"""完全二叉树"""def __init__(self, node=None):self.root = nodedef add(self, item):"""添加节点"""if self.root is None:self.root = Node(item)return# 队列queue = [self.root]# 从尾部添加数据while True:# 从头部取出数据node = queue.pop(0)# 判断左节点是否为空if node.lchild is None:node.lchild = Node(item)returnelse:queue.append(node.lchild)if node.rchild is None:node.rchild = Node(item)returnelse:queue.append(node.rchild)

五、二叉树的遍历

树的遍历:是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次,我们把这种对所有节点的访问称为遍历(traversal)。

树的两种重要的遍历模式是:深度优先遍历广度优先遍历。深度优先一般用递归,广度优先一般用队列。一般情况下能用递归实现的算法大部分也能用堆栈来实现。

1、广度优先遍历

广度优先遍历:从树的root开始,从上到下从从左到右遍历整个树的节点

2、深度优先遍历

深度优先搜索(Depth First Search):对于一颗二叉树,深度优先搜索(Depth First Search)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。深度遍历有重要的三种方法。这三种方式常被用于访问树的节点,它们之间的不同在于访问每个节点的次序不同。

三种深度优先遍历方式:

  • 先序遍历(preorder):根 左 右
  • 中序遍历(inorder):左 根 右
  • 后序遍历(postorder):左 右 根
    在这里插入图片描述
    在这里插入图片描述
    根据深度遍历结果反推二叉树的结构:由中序遍历&先序遍历 或者 中序遍历&后序遍历 的遍历结果就可以推出二叉树的结构
    在这里插入图片描述

3、二叉树遍历的代码实现

class Node(object):"""节点类"""def  __init__(self, item):self.item = itemself.lchild = Noneself.rchild = Noneclass BinaryTree(object):"""完全二叉树"""def __init__(self, node=None):self.root = nodedef add(self, item):"""添加节点"""if self.root == None:self.root = Node(item)return# 队列queue = []# 从尾部添加数据queue.append(self.root)while True:# 从头部取出数据node = queue.pop(0)# 判断左节点是否为空if node.lchild == None:node.lchild = Node(item)returnelse:queue.append(node.lchild)if node.rchild == None:node.rchild = Node(item)returnelse:queue.append(node.rchild)def breadh_travel(self):"""广度优先遍历"""if self.root == None:return# 队列queue = []# 添加数据queue.append(self.root)while len(queue)>0:# 取出数据node = queue.pop(0)print(node.item, end="")# 判断左右子节点是否为空if node.lchild is not None:queue.append(node.lchild)if node.rchild is not None:queue.append(node.rchild)def preorder_travel(self, root):"""先序遍历 根 左 右"""if root is not None:print(root.item, end="")self.preorder_travel(root.lchild)self.preorder_travel(root.rchild)def inorder_travel(self, root):"""中序遍历 左 根 右"""if root is not None:self.inorder_travel(root.lchild)print(root.item, end="")self.inorder_travel(root.rchild)def postorder_travel(self, root):"""后序遍历 根 左 右"""if root is not None:self.postorder_travel(root.lchild)self.postorder_travel(root.rchild)print(root.item, end="")if __name__ == '__main__':tree = BinaryTree()tree.add("0")tree.add("1")tree.add("2")tree.add("3")tree.add("4")tree.add("5")tree.add("6")tree.add("7")tree.add("8")tree.add("9")tree.preorder_travel(tree.root)print()tree.inorder_travel(tree.root)print()tree.postorder_travel(tree.root)

这篇关于数据结构-非线性结构-树形结构:有序树 ---->二叉树【动态数据结构】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1128844

相关文章

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

PostgreSQL如何查询表结构和索引信息

《PostgreSQL如何查询表结构和索引信息》文章介绍了在PostgreSQL中查询表结构和索引信息的几种方法,包括使用`d`元命令、系统数据字典查询以及使用可视化工具DBeaver... 目录前言使用\d元命令查看表字段信息和索引信息通过系统数据字典查询表结构通过系统数据字典查询索引信息查询所有的表名可

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作