二叉树基础(上):如何遍历二叉树?
二叉树
二叉树,顾名思义,每个结点最多有两个“叉”,也就是两个子节点,分别是左子节点和右子节点。不过,二叉树并不要求每个结点都必须有两个子节点,可以只有左子节点或者只有右子节点。
最坏情况下,二叉树退化成链表,也就是每个节点只有左子节点或右子节点,这种情况下,二叉树就跟链表没有什么区别了。
满二叉树
,除叶子节点外,每一层每一个节点都两个子节点的二叉树。满二叉树很好理解,只要看这颗二叉树的每一个节点有没有缺失,除了叶子节点外,其他的节点的有没有两个子节点就行了。
完全二叉树
,最后一层叶子节点都靠左排列,并且除了最后一层,其他层的节点个数达到最大。
如何存储二叉树?
有两种存储方式,一种是基于链表的链式存储法,一种是基于数组顺序存储法。
链式存储
我们先来看链式存储法,每个节点有三个字段,其中一个存储数据,另外两个存储指向左右子节点的指针。链式存储法看起来很直观,大部分的代码都是通过链表这种结构实现的。
顺序存储
我们在做 leetcode 二叉树部分的代码时,能发现每次题目给的输入出都是数组这种形式,这其实就是二叉树的顺序存储方式。
普通二叉树
3
\
9 20
\
15 6
9, 20, null, null, 15, 6]
完全二叉树
1
\
2 3
\ /
4 5 6
2, 3, 4, 5, 6]
我们不难看出,二叉树的顺序存储是按照从上往下,从左往右依次访问二叉树节点的,空节点的地方在数组中存储 null
。
我们发现,二叉树的顺序存储,在数组中出现元素为空的情况,这样就浪费了大量的存储空间。
所以,如果一棵完全二叉树,用数组存储无疑是最节省内存的一种方式。因为数组的存储方式不需要像链表那样,要存储额外的左右子节点的指针。这也是为什么完全二叉树要求最后一层的子节点都靠左的原因。
二叉树的遍历
前中序三种遍历方式的区别就是访问根节点的顺序
-
前序遍历, 根-左-右 -
中序遍历, 左-根-右 -
后序遍历, 左-右-根 -
层序遍历,一层一层地遍历
实际上,二叉树的前、中、后序遍历就是一个递归的过程。比如,前序遍历,其实就是先打印根节点,然后递归地打印左子树,最后递归地打印右子树
二叉树遍历的时间复杂度
二叉树每个节点最多会被访问两次,所以遍历操作的时间复杂度,跟节点个数 n 成正比,也就是说二叉树遍历的时间复杂度是 O(n)。