二叉树的分类
二叉树分为满二叉树,完全二叉树,二叉搜索树,平衡二叉搜索树。
满二叉树(如图)
一颗二叉树只有度为0和度为2的节点,度为0的节点在同一层,这就是一个满二叉树。也可以说成是深度为k,有2的k次方-1个节点。
完全二叉树(如图)
拓展:有很多语言中都存在优先级队列其实是⼀个堆(大顶堆和小顶堆),堆就是⼀棵完全⼆叉树,同时保证⽗⼦节点的 顺序关系
⼆叉搜索树
前面的满二叉树和完全二叉树都是没有数值的,而二叉搜索树是有数值的。它是一个有序的树故又称二叉排序树。规律如下
若它的左⼦树不空,则左⼦树上所有结点的值均⼩于它的根结点的值;
平衡⼆叉搜索树
说白了,平衡二叉搜索树 它要么是⼀棵空树要么它的左右两个⼦树的⾼度差的绝对值不超过1,并且左右两个⼦树都是⼀棵平衡⼆叉树。
如图:
最后⼀棵 不是平衡⼆叉树,因为它的左右两个⼦树的⾼度差的绝对值超过了1。
拓展:C++中map、set、multimap,multiset的底层实现都是平衡⼆叉搜索树,所以map、set 的增删操作时间时间复杂度是logn,注意我这⾥没有说unordered_map、unordered_set,
二叉树的存储方式
二叉树的存储方式分为两种:链式存储和顺序存储。
链式存储
二叉树的链式存储和链表的存储方式其实是一致的,只不过二叉树是两个指针,一个左指针,一个右指针,分别用来指向他的左右孩子节点,而链表仅有一个指针,指向他的下一个节点,这两者本质其实是一样的。
链式存储图如下:
顺序存储
顺序存出无非就是用数组来存储二叉树的左右孩子,其内存是连续分布的。这一点和链式存储是有所区别的,链式存储是通过指针把分布在散落 在各个地址的节点串联⼀起。
顺序存储图如下:
那么大家不难想到,用数组存储二叉树如何遍历呐?
如果父节点而数组下标为i的话,那么他的左右孩子的下标分别为 2i + 1, 2i+2。一般我们比较常用的还是链式存储,但是也要知道 可以用数组来存储二叉树。
二叉树的遍历方式
二叉树主要有两种遍历方式:深度优先遍历、广度优先遍历。这两种遍历方式就类似于图论中的深度优先搜索和广度优先搜索。
深度优先搜索
深度优先搜索说白了,就是顺着二叉树的根节点,先往深⾛,遇到叶⼦节点再往回⾛。一些有基础的同学一听到深度优先搜索可能第一反应就是,前序遍历,中序遍历,后序遍历。可是也仅仅是了解,下面我就来深度讲解一下:
深度优先遍历:
前序遍历(中左右)递归法 迭代法
中序遍历(左中右)递归法 迭代法
后序遍历(左右中)递归法 迭代法
广度优先遍历
就是一层一层的去遍历。主要的遍历方法就是迭代法。
深度优先遍历和广度优先遍历小总结:
深度优先遍历一般我们都是使用递归法来解决的,其实栈这种数据结构底层就是用递归来实现的(先进后出),所以说每次每一次出栈都要等到上面的元素都出去了当前元素才能出去,就像递归必须等到里面的函数执行完并且返回数值的时候,当前的函数才能继续往下执行。
深度优先搜素一般是使用队列来实现的,利用队列先进先出的特性来实现一层一层的遍历。
二叉树的定义
上面我们也说了二叉树主要有两种存储方式:链式存储和顺序存储。顺序存储就是⽤数组来存, 这个定义没啥可说的。下面我们就来看看链式存储的二叉树节点定义的方式:
js定义二叉树:
function TreeNode(){
this.val = null;
this.left = null;
this.right = null;
}
c++定义二叉树:
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left (NULL),right(NULL){}
};
节点的定义很重要,力扣上会默认给出节点的定义,而在面试过程中,面试官可能让我们手写出完整的代码逻辑。这时候就需要我们不仅写出主要的代码逻辑,一些基本的数据结构的定义也要能写出来。不过牛客网是不会给出默认定义的,全程需要自主实现。
以上就是主要介绍了二叉树的理论基础,主要介绍了二叉树的种类、存储方式、遍历方式以及定义,比较全面的介绍了二叉树各方面的重点。扫了一遍基础。
加油哦!!!