二叉树
二叉树两种主要的形式:满二叉树和完全二叉树。
满二叉树:如果一颗二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树。即深度为k,有2^k-1个节点的二叉树。
完全二叉树:在完全二叉树中,除了最底层节点可能每填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的位置。若最底层为第h层(h从1开始),则该层包含1~2^(h-1)个节点。
二叉搜索树
满二叉树和完全二叉树没有数值,而二叉搜索树是有数值的,二叉搜索树是一个有序树。
若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左、右子树也分别为二叉排序树
平衡二叉搜索树
平衡二叉搜索树,又叫AVL树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间复杂度是logn。 unordered_map和unordered_set的底层实现是哈希表。
二叉树的存储方式
二叉树可以链式存储,也可以顺序存储。
链式存储用指针,顺序存储就用数组。
顾名思义,顺序存储的元素在内存中是连续分布的,链式存储则是通过指针把分布在各个地址的节点串联在一起。
如果用数组来存储二叉树如何遍历?数组下标:0 1 2 3 4 5 6 7 ……
如果父节点的数组下标是i,那么它的左孩子就是i*2+1,右孩子就是i*2+2。
二叉树的遍历方式
二叉树主要有两种遍历方式:
深度优先遍历:先往深走,遇到叶子节点再往回走。
广度优先遍历:一层一层地区遍历。
这两种遍历是图论中最基本到的两种遍历方式,后面在介绍图论的时候还会介绍到。那么从深度优先遍历和广度优先遍历进一步拓展,才有如下遍历方式:
深度优先遍历 ->
前序遍历(递归法,迭代法)
中序遍历(递归法,迭代法)
后序遍历(递归法,迭代法)
广度优先遍历 ->
层次遍历(迭代法)
深度优先搜索中的三个顺序,前中后遍历,前中后指的是中间节点的遍历顺序
前序遍历:中左右
中序遍历:左中右
后续遍历:左右中
二叉树中深度优先和广度优先遍历1实现方式,我们做二叉树相关题目,经常会使用递归的方式来实现深度优先遍历,也就是实现前中后序遍历,使用递归是比较方便的。
之前我们讲栈与队列的时候,就说过栈其实就是递归的一种实现结构,也就是说前中后序遍历的逻辑都可以借助栈使用递归的方式来实现。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。
二叉树的定义
前面说二叉树有两种存储方式顺序存储,和链式存储,顺序存储就是用数组来存,链式存储:
定义方式
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x),left(NULL),right(NULL){}
};
上面二叉树的定义和链表类似,相对于链表,二叉树的节点里多了一个指针,有两个指针,指向左右孩子。
注意书写节点的定义!!!
总结:
二叉树是一种基础数据结构,在算法面试中都是常客,也是众多数据结构的基石。