前言
开启算法新征程,为了让我对二叉树有新层次的理解,加油学习吧。
二叉树的种类
二叉树的两种形式:满二叉树和完全二叉树
满二叉树
只有度为0和度为2的节点的树,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
如下图:
深度:k
节点个数:2^k-1
完全二叉树
除了最底层的节点没有安排满外,其余每层节点数都达到最大值,并且最下面一层节点都集中在该层最左的若干位置。 若最底层为第 h 层,则该层包含 1~ 2h 个节点。
要注意完全二叉树的样子:
PS:优先队列其实是一个堆,堆就是一颗完全二叉树,同时保证父子节点的顺序关系。
二叉搜索树
前面介绍的树,都是没有数值的。而二叉搜索树,是有数值的。而且二叉搜索树, 是一个有序树。
它有以下特点:
- 若它的左子树不为空,则左子树上所有节点的值,均小于它的根节点的值。
- 若它的右子树不为空,则右子树上所有节点的值,均大于它的根节点的值。
- 它的左、右子树也分别是二叉排序树。
如下图,两个都是搜索树:
平衡二叉搜索树
性质:它是一棵空树,或者它的左右两个子树的高度差的绝对值不超过1,并且两个子树都是一棵平衡二叉树。
如下图:
可以看出,最后一棵树,左右子树高度差超过了1。
重点来了:
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树
所以map、set的增删操作时间时间复杂度是logn。
unordered_map、unordered_map底层实现是哈希表。
二叉树的存储方式
二叉树可以链式存储,也可以顺序存储
链式存储,用指针;顺序存储,用数组。
链式存储,如下图:
用数组存储的顺序存储如下图:
它的节点如何遍历?
如果父节点的数组下表是i,那么它的左孩子就是i * 2 + 1,右孩子就是 i * 2 + 2。
但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。
二叉树的遍历方式
深度优先遍历:先往深走,遇到叶子节点再往回走。
广度优先遍历:一层一层的去遍历。
这两种遍历是图论中最基本的两种遍历方式。
如下图:
之前我们讲栈与队列的时候,就说过栈其实就是递归的一种是实现结构,
也就说前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,
因为需要先进先出的结构,才能一层一层的来遍历二叉树。
这里其实我们又了解了栈与队列的一个应用场景了。
二叉树的代码描述
c++代码如下:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
二叉树的定义 和链表是差不多的,相对于链表 ,二叉树的节点里多了一个指针, 有两个指针,指向左右孩子.
总结
二叉树是一种基础数据结构,在算法面试中都是常客,也是众多数据结构的基石。
本篇介绍了二叉树的种类、存储方式、遍历方式以及代码描述,比较全面的介绍了二叉树各个方面的重点。