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

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

相关文章

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

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

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2