二叉树的定义:
形如这个亚子的就是二叉树咯;二叉树就是说,他的每一个结点最多只有两个孩子结点。不能再多了。
二叉树特点:
1.它的左右孩子是严格区分的,左孩子和右孩子是不一样的。
2.五种基本形态的二叉树
- 空树
- 只有一个根节点
- 根节点只有左子树
- 根节点只有右子树
- 根节点有左右子树
特殊的二叉树:
1.斜树
2.满二叉树
3.完全二叉树
完全二叉树其实很好理解,他和满二叉树是由关系的,我们可以这样理解,先对满二叉树从上到下,从左到右编号,然后拿着另外一个二叉树来对比,如果这个二叉树上的结点以及编号和满二叉树的结点编号能一一对应的上,那么就是完全二叉树。
二叉树的性质:
性质一:
性质二:
性质三:
性质四:
性质五:
二叉树的存储结构:
顺序存储结构:
注意这里的下标是从1开始的,不是从0,因为为了计算方便,如果是0,乘什么都是0。
上面对于一般的非完成二叉树是怎么处理的呢?其实就是开辟空间的话还是开辟一个满二叉树的空间,只是在没有数据的那个点上赋值为空就行了,但是这样会出现一个很大的问题,那就是在斜树的情况下是极度浪费空间的。
链式存储结构:
二叉树的操作:
二叉树的遍历:
第一种:递归方式
使用了java的都知道,遍历就是访问一个容器中的所有元素,那么这里二叉树的遍历就是说按照一定的顺序访问完所有的结点。
递归先序遍历:
加上上面的步骤后我们加上自己的理解:
其实这里面涉及到了递归的概念,就是返回来调用自己。
我们这里把这个三个步骤看成是一个完成的程序,想象成他是一个被封装的函数。那么首先第一步找到这个树的根节点,然后找左子树,注意这个时候左子树其实也是一颗树,那么访问的时候又要回到函数最开始的那一步,这就用到了递归调用。所以又是先访问这个子树的根节点,然后继续查看有没有左子树,有的话继续访问,没有的话就说明左子树访问完成,访问右子树,右子树也是树,那么又是重复上面的步骤。
比如上面的这棵树。对于一整颗数来说我们先访问根节点A,然后访问左子树,这个时候左子树的根节点又是B,继续访问左子树,根节点为D,继续访问左子树,为空!访问右子树,根节点为G,左右子树都是空,左边的子树遍历完成,遍历根节点A的右子树,依次来讲就是,访问C,然后访问E,然后访问F。
所以最终的遍历结果为:A、B、D、G、C、E、F so easy!
递归中序遍历:
中序遍历也是用到了递归的思想,当明白了递归的用处之后真的只能感叹!妙啊~
通过这个如来解释,同样我们把上面的三个步骤封装成一个函数,那么首先第一步:访问整个数的左子树,那么就是B为根节点的树,开始递归调用,又访问左子树,就是D为根节点的树,继续,这个时候D的左子树为空,走下一步,访问根节点,这个时候子树的根节点是D,所以遍历到第一个元素为D,然后访问右子树,G,G的左子树为空,往下走一步访问根节点G,然后访问右子树,为空,返回,这个时候层层返回,返回到B为根节点的子树,因为他的左子树已经遍历完成,这个时候访问根节点B,然后是他的右子树,为空,返回到根节点为A,遍历到A元素,然后访问A为根节点的右子树,依次类推。所以整个遍历下来的元素为:D、G、B、A、E、C、F so easy~
递归后序遍历:
有了前面递归遍历的经验我们很容易知道后序遍历是怎么实现的。
我们以上面这个图来说,我们先左子树,然后右子树,最后遍历根节点。所以这个树的后序遍历为:G、D、B、E、F、C、A
第二种:非递归方式:
非递归方式的同样有先序、中序、后序遍历模式,但是他们的代码实现是不一样的。这里用到的是栈。但是他们的访问顺序的核心思想是没有变的。
第三种:层序遍历
这个方式是十分清除明了的,他就是按照从上往下,从左往右的方式一层一层的遍历。
比如下面这个图遍历出来的顺序就是A B C D E F G
这里需要用到队列这个数据结构