数据结构——树和二叉树
树
树的定义
树(Tree)是 n(n≥0)个结点的有限集,它或为空树(n = 0);或为非空树,对于非空树 T:
有且仅有一个称之为根的结点;
除根结点以外的其余结点可分为 m(m>0)个互不相交的有限集 T1, T2, …, Tm, 其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。
树是 n 个结点的有限集
树的其他表示方式
树的概念
每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;
除了根节点外,每个子节点可以分为多个不相交的子树;
树的基本术语
根:即根结点(没有前驱)
叶子:即终端结点(没有后继)
节点:即树的数据元素
节点的度:一个节点含有的子树的个数称为该节点的度;
树的度:一棵树中,最大的节点的度称为树的度;
叶节点或终端节点:度为零的节点;
分支节点:即度不为 0 的结点(也称为内部结点)
父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
兄弟节点:具有相同父节点的节点互称为兄弟节点;
节点的层次:从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推;
树的高度或深度:树中节点的最大层次;
堂兄弟节点:父节点在同一层的节点互为堂兄弟;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
森林:由 m(m>=0)棵互不相交的树的集合称为森林;
树的种类
无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;
有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
二叉树:每个节点最多含有两个子树的树称为二叉树;
完全二叉树:对于一颗二叉树,假设其深度为 d(d>1)。除了第 d 层外,其它各层的节点数目均已达最大值,且第 d 层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树,其中满二叉树的定义是所有叶节点都在最底层的完全二叉树;
平衡二叉树(AVL 树):当且仅当任何节点的两棵子树的高度差不大于 1 的二叉树;
排序二叉树(二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树);
霍夫曼树(用于信息编码):带权路径最短的二叉树称为哈夫曼树或最优二叉树;
B 树:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多余两个子树。
常见应用场景
xml,html 等,那么编写这些东西的解析器的时候,不可避免用到树
路由协议就是使用了树的算法
mysql 数据库索引
文件系统的目录结构
所以很多经典的 AI 算法其实都是树搜索,此外机器学习中的 decision tree 也是树结构
二叉树
二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)
有且仅有一个称之为根的结点;
除根结点以外的其余结点分为两个互不相交的子集 T1 和 T2,分别称为 T 的左子树和右子树,且 T1 和 T2 本身又都是二叉树。
基本特点
结点的度小于等于 2
有序树(子树有序,不能颠倒)
二叉树的性质
在二叉树的第 i 层上至多有 2^(i-1)个结点
深度为 k 的二叉树至多有 2^(k-1)个结点
对于任何一棵二叉树,若 2 度的结点数有 n2 个,则叶子数 n0 必定为 n2+1 (即 n0=n2+1)
具有 n 个结点的完全二叉树的深度必为[log2n]+1
对完全二叉树,若从上至下、从左至右编号,则编号为 i 的结点,其左孩子编号必为 2i,其右孩子编号必为 2i+1;其双亲的编号必为 i/2。
二叉树节点表示
案例 ly01.py
二叉树遍历
深度优先,一般用递归
先序(Preorder)
中序(Inorder)
后序(Postorder)
广度优先,一般用队列
满二叉树
除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。
国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为 K,且结点总数是(2^k) -1 ,则它就是满二叉树。
满足等比数列公式,具有如下性质
满二叉树的结点数一定是奇数个
第 i 层上的结点数为:2^i-1
层数为 k 的满二叉树的叶子结点个数(最后一层): 2^k-1
国外(国际)定义:a binary tree T is full if each node is either a leaf or possesses exactly two childnodes.(如果一棵二叉树的结点要么是叶子结点,要么它有两个子结点,这样的树就是满二叉树。(一棵满二叉树的每一个结点要么是叶子结点,要么它有两个子结点,但是反过来不成立,因为完全二叉树也满足这个要求,但不是满二叉树))
度为 0 或者 2,不存在度为 1 的结点
满二叉树和完全二叉树的区别
满二叉树是叶子一个也不少的树,而完全二叉树虽然前 n-1 层是满的,但最底层却允许在右边缺少连续若干个结点。满二叉树是完全二叉树的一个特例。![在这里插入图片描述](https://img-blog.csdnimg.cn/20191115204148548.png =350x300) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191115204156860.png =350x300)
C++代码实现
python 代码实现
线索二叉树
对一个非线性结构进行线性化操作,使每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个直接前驱和直接后继。
n 个结点的二叉链表中必定存在 n+1 个空链域,因此可利用这些空链域来存放结点的前驱和后继信息。
二叉链表加一头结点,lchild 域的指针指向二叉树的根结点,rchild 域的指针指向中序遍历时访问的最后一个结点。
二叉树中序序列中第一个结点的 lchild 域的指针和最后一个结点 rchild 域的指针均指向头结点。
线索二叉树的术语
线索:指向结点前驱和后继的指针
线索链表:加上线索二叉链表
线索二叉树:加上线索的二叉树(图形式样)
线索化:对二叉树以某种次序遍历使其变为线索二叉树的过程
树和森林
树的存储结构
双亲表示法
以一组连续空间存储树的结点,同时在结点中附设一个指针,存放双亲结点在链表中的位置。
特点:找双亲容易,找孩子难
孩子链表表示法
每个结点有多个指针域,分别指向其子树的根。
树的二叉链表(孩子-兄弟)存储表示法
将树转化为二叉树
加线:在兄弟之间加一连线
抹线:对每个结点,除了其左孩子外,去除其与其余孩子之间的连线
旋转:以树的根结点为轴心,将整棵树顺时针转 45°
树转换成的二叉树其右子树一定为空
将二叉树转换成树
加线:若 p 结点是双亲结点的左孩子,则将 p 的右孩子,右孩子的右孩子,……沿分支找到的所有右孩子,都与 p 的双亲用线连起来
抹线:抹掉原二叉树中双亲与右孩子之间的连线
调整:将结点按层次排列,形成树结构
树的先序遍历与二叉树先序遍历相同树的后序遍历相当于对应二叉树的中序遍历
版权声明: 本文为 InfoQ 作者【若尘】的原创文章。
原文链接:【http://xie.infoq.cn/article/a79724c99e227a6c323895bde】。文章转载请联系作者。
评论