![7964a38269cc99d044733dd9222dbcd6.png](https://i-blog.csdnimg.cn/blog_migrate/b4be5097528c669a5ec83c7cff0a6c70.jpeg)
要知道二叉树是一种特殊的树,了解二叉树之前就需要知道什么是树啦。
1 树
树是n个(n>=0)结点的有限集,n=0的时候称为空树。呵,空树有什么意思?
![7f3088be-692d-eb11-8da9-e4434bdf6706.png](http://p04.5ceimg.com/content/7f3088be-692d-eb11-8da9-e4434bdf6706.png)
在任意一个非空的树中,都满足这两个特性:
- 有且仅有一个根结点;
- n>1的时候,其余结点可以分成m(m>0)个互不相交的有限集,且每一个集合本身又是一颗树,称为根的子树;
需要注意:根节点只有一个,子树可以有多个,但是一定互不相交!
![813088be-692d-eb11-8da9-e4434bdf6706.png](http://p03.5ceimg.com/content/813088be-692d-eb11-8da9-e4434bdf6706.png)
如图,只有一个根结点1,但是每个结点的子树个数可以任意,有1个的,也有3个的。
几个概念
- 结点的度
结点拥有的子树数目称为该节点的度。
![32c3b485975bd361a556c7100c59b3f0.png](https://i-blog.csdnimg.cn/blog_migrate/d1152083bdb104acabc2499bc207bd6a.jpeg)
- 结点关系
父结点:如上图,1为2的父结点。
子结点:2为1的子结点。
兄弟结点:父结点相同的结点互为兄弟结点,2,44,6互为兄弟结点。
- 结点层次
从根开始定义,根为第0层,根的子结点为第1层,以此类推;
树的基本概念介绍到这里,是时候请出真正的主角了!
2 二叉树
二叉树是每个结点最多有两个子结点的树结构。
有且仅有一个根结点,对左右子树严格区分。
有两个特性:
- 二叉树每个结点的度都小于等于2;
- 第k层结点的最大个数为2^(k-1);
![44b7b52053ef6554be5354a0506392d2.png](https://i-blog.csdnimg.cn/blog_migrate/86780011924a1fa5d09bac29f7f09cfc.jpeg)
下面介绍几种特殊的树,应用也非常广泛啦~
3 满二叉树
假设一棵树的深度为k,那么具有2^k-1个结点的二叉树就叫做满二叉树。
![1cba497d673e260def90bebec095ee07.png](https://i-blog.csdnimg.cn/blog_migrate/fd0a833d0f16420c46a45d73670cea68.jpeg)
每一层上的结点数都是最大结点数,第i层就有2^(i-1)个结点;
大白话:就是说除了最后一层结点没有任何子结点外,余下每一层上结点都有两个子结点;
有人要问了,2^k-1是什么鬼,咋来的?
对于一个满二叉树,第一层1个结点,第二层2个结点,第三层4个结点,以此类推,第k层就有2^(k-1)个结点,总结点数就是(1+2+4+…+2^(k-1))=2^k-1。
这里用到等比数列求和公式。
4 完全二叉树
完全二叉树的概念是由满二叉树引出的;
4.1 一个判断准则
如果二叉树的层数为k,那么满足下面两个条件的即为完全二叉树:
- 除了第k层,其他(1~k-1)层的结点数都达到最大个数(就是每个结点都有两个子结点,度为2);
- 第k层所有结点都连续集中在最左边;
因此完全二叉树有如下特性:
- 所有的叶结点都在第k层或第k-1层;
- 对于任意一个结点,如果他的右子树最大层次为L,那么他左子树的最大层次一定为L或者L+1;
![26878be87ba37ef4c2bb7647d27d1a0e.png](https://i-blog.csdnimg.cn/blog_migrate/87b5d3dd7b3d79394a9faee0ac67a189.jpeg)
完全二叉树1:
![23b9a0601079563b8f2737bd1375162f.png](https://i-blog.csdnimg.cn/blog_migrate/128e63ce4dd02ad532ec090d2099dbd9.jpeg)
不完全二叉树1:违背条件1,倒数第二次的节点数量不是最大。
![cc098533e574923e14fd83067866ef79.png](https://i-blog.csdnimg.cn/blog_migrate/584a50d1c64f921b4aad8595f09b2d3d.jpeg)
不完全二叉树2:违背条件2,最后一层的结点没有连续集中在最左侧。(二叉树对于左右子树严格区分)
![44b7b52053ef6554be5354a0506392d2.png](https://i-blog.csdnimg.cn/blog_migrate/86780011924a1fa5d09bac29f7f09cfc.jpeg)
4.2 另一个判断准则
假定二叉树的编号是按照从上到下,从左到右的顺序编号,那么对于深度为K的,有n个结点的二叉树,当且仅当
其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
![67e11a48dd1061e621e3512033769641.png](https://i-blog.csdnimg.cn/blog_migrate/7e144e3d0c5d55394e0285098cae4438.jpeg)
其实也就想表达第一个判断准则中两个条件的意思啦。
一些小性质
假设完全二叉树的结点总数是n,n0表示度为0的结点数,n1表示度为1的结点数,n2表示度为2的结点数。
- 因此有n=n0+n1+n2;
- 度为2的结点有两个子结点,度为1的结点有一个子结点,在加上一个根结点,所以有n=1+n1+2*n2;
- 根据完全二叉树的定义,可以知道n1=0或者1,只有这两种情况。
5 斜树
斜树是二叉树的极端情况。左斜树:所有结点都只有左子树的二叉树;
![6652efe4ae111ef8715fe2edc579a1f4.png](https://i-blog.csdnimg.cn/blog_migrate/93663071865c59ad57e91f3ef1bdff48.jpeg)
右斜树:所有结点都只有右子树的二叉树;
![9c7c671a3afd215d495d773fbc561181.png](https://i-blog.csdnimg.cn/blog_migrate/1bfd3c95005f6895d396e2257f9a21c9.jpeg)
6 二叉树的存储
顺序存储
使用一维数组存储二叉树中的节点,先对二叉树进行从上到下,从左到右编号,节点所在编号就是其在一维数组中的索引;
不逼逼废话,举例最直观了。
![63a505ec368ea25ace2b3aefb4a773c9.png](https://i-blog.csdnimg.cn/blog_migrate/fb0e6424a5b010a9190865e0e0f447bb.jpeg)
对下面这个完全二叉树进行顺序存储,这里为了简便,每个结点的值也是该结点的编号。
![67e11a48dd1061e621e3512033769641.png](https://i-blog.csdnimg.cn/blog_migrate/7e144e3d0c5d55394e0285098cae4438.jpeg)
![f6d65ffd9a349d39e3e5ba8f636ab316.png](https://i-blog.csdnimg.cn/blog_migrate/78a15a4f5a2222354079230c045bf7ea.jpeg)
二叉树是完全二叉树或者是满二叉树的时候,结点数=数组数,刚好填满;
噢哟,那很不错哦!
![fd05515e64927ae44329d2f9e927d63c.png](https://i-blog.csdnimg.cn/blog_migrate/8626bd0f3dc220dabdf3ea4157d90250.jpeg)
当二叉树是不完全二叉树的时候,如果采取顺序存储,会出现空间浪费;
什么?这是人家不想看到的呢!
![cad004b91e4e9dccd0f9ac74bbfe8288.png](https://i-blog.csdnimg.cn/blog_migrate/c1dd523c6d77e236770a370fad9338ec.jpeg)
如对下面这个不完全二叉树进行顺序存储,其中灰色表示缺失的节点,虽然缺失,但是编号的时候还是按照满二叉树结点形式进行编号;
![bd1630cf140947fb49514c843882f47f.png](https://i-blog.csdnimg.cn/blog_migrate/04433d3ea49a5688386270509c6b9155.jpeg)
![c335844a012f55365845946709fc4c78.png](https://i-blog.csdnimg.cn/blog_migrate/f8ae36b2c1bb2d214348f457155572f4.jpeg)
数组中的#就表示此处没有存储结点。
极端情况如斜树,采取顺序存储的方式是十分浪费空间的;
![d845d1be5c33a0f04099e8af1d9139a3.png](https://i-blog.csdnimg.cn/blog_migrate/2eb7f234f8c609f46debab424df58b2e.jpeg)
![8bdfd2e797715f92ebbc715bf300bc99.png](https://i-blog.csdnimg.cn/blog_migrate/1a122d128ac0a9b0746b4c2f91c22152.png)
这都浪费了一半了吗?
![068fdd41af8cddbcfc1dccdff1054157.gif](https://i-blog.csdnimg.cn/blog_migrate/1d148cf237c41a29b9812a2cc61284e7.gif)
这怎么能忍!
链表存储
好在我们还有大招!二叉树每个结点最多有两个子结点,因此将结点的数据结构定义为一个数据和两个指针域,分别表示结点值和左右子结点;
每个指针可以准确指向子结点,因此链表存储能够有效利用空间,避免浪费。
struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} };
![ce756f2f33a5e33b3bccd6389202e440.png](https://i-blog.csdnimg.cn/blog_migrate/3390ac78800f58c495692d48e20b6816.jpeg)
7 二叉树的遍历
根据根结点的遍历顺序,分为前中后三种遍历方法。
- 前序遍历:根结点-左结点-右结点
- 中序遍历:左结点-根结点-右结点
- 后序遍历:左结点-右结点-根结点
这三种遍历可以用递归或者栈的方法实现。还有一种
- 层次遍历:从上至下,逐层遍历
一般用递归或队列的方式实现。
![23b9a0601079563b8f2737bd1375162f.png](https://i-blog.csdnimg.cn/blog_migrate/128e63ce4dd02ad532ec090d2099dbd9.jpeg)
对于上图所示的二叉树,前序遍历:1,3,3,5,6;中序遍历:3,2,5,1,6;
后序遍历:3,5,2,6,1;
层次遍历:1,2,6,3,5;
到这里二叉树的基础知识就讲完啦,是不是有种原来如此的感觉?
![df872a5e4d7cac809ad86f2323705819.gif](https://i-blog.csdnimg.cn/blog_migrate/8719310793eff59a9b3ddd5e4d2f0468.gif)
呼呼~最后和我大喊一声妈妈,我也知道什么叫二叉树啦!
以上内容改编自于我的算法公众号,如果觉得我写的还不错的话,关注我吧!
公众号搜索:易行时光
里面有更多有关算法和数据结构的知识哦,从此小白也能搞懂算法啦~
![10b3fe8a08e88befe3422f9860d6319f.gif](https://i-blog.csdnimg.cn/blog_migrate/24e695da6c961cdd37ef4506c73e1a66.gif)