学习笔记|数据结构——二叉树

学习笔记|数据结构——二叉树


树示意图
每个元素叫做”节点“;用线连接的相邻节点之间的关系,叫作父子关系
父节点是同一个节点的一群节点互称为兄弟节点
没有父节点的节点叫作根节点
没有子节点的节点叫作叶子节点
节点的高度:节点到叶子节点的最长路径(边数)
节点的深度:根节点到这个节点所经历的边的个数
节点的层数:节点的深度+1
树的高度:根节点的高度,即叶节点到根节点的最长路径

高度这个概念可以想象成楼的高度,是从下往上数的,树的高度也是一样,从最底层开始计数,并且计数的起点是0
深度这个概念可以想想成水中鱼的深度,是从上往下数的,从根节点开始度量,并且计数起点也是0
层数跟深度的计算类似,不过计数起点是1,根节点位于第1层
高度、深度、层的概念
二叉树——非线性表结构
二叉树每个节点最多有两个叉,就是两个子节点,分别是左子节点和右子节点。二叉树并不要求每个节点都有两个子节点
满二叉树:叶子节点全部都在底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树叫作满二叉树
完全二叉树:叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫作完全二叉树。
完全二叉树示意图
存储一棵二叉树
二叉链式存储法:每个结点有三个字段,其中一个存储数据,另外两个指向左右节点的指针,我们只要拎住根节点,就可以通过左右子节点的指针,把整棵树都穿起来
二叉链式存储法
基于数组的顺序存储法:把根节点存储在下标i=1的位置,左子节点存储在下标2i=2的位置,右子节点存储在2i+1 = 3的位置,以此类推。
如果节点X存储在数组中下标为i的位置,下标为2i的位置存储的就是左子节点,下标为2i+1的位置存储的就是右子节点。下标为i/2的位置存储的就是它的父节点。只要知道根节点存储的位置,通过计算下标,就可以把整棵树穿起来
一般情况下,为了计算方便子节点,根节点会存储在下标为1的位置
基于数组的顺序存储法
这就是完全二叉树存在的意义。对于完全二叉树,用数组存储是最节省内存的一种方式。因为数组的存储方式并不需要像链式存储法那样,要存储额外的左右子节点的指针。堆其实就是一种完全二叉树,最常用的存储方式就是数组
二叉树的遍历
前序遍历、中序遍历、后序遍历。其中,前、中、后序,表示的是节点与它的左右子树节点遍历打印的先后顺序
前序遍历:本节点——左节点——右节点
中序遍历:左节点——本节点——右节点
后序遍历:左节点——右节点——本节点
二叉查找树
二叉查找树要求,在树中的任意一个节点,在其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。
二叉查找树示意图
二叉查找树的查找操作
先取根节点,如果它等于要查找的数据,那就返回。如果要查找的数据比根节点的值小,就在左子树中递归查找;如果要查找的数据比根节点的值大,就在右子树中递归查找
查找操作示意图
二叉查找树插入操作
新插入的数据一般都是在叶子节点上,只需从根节点开始,依次比较要插入的数据和节点的大小关系。
如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接查到右子节点位置;如果不为空,就再递归遍历右子树,查找插入位置;
如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置
二叉查找树插入操作
二叉查找树的删除操作
针对要删除节点的子节点数的不同,需要分三种情况处理
1、如果要删除的节点有两个子节点,需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除这个最小节点。因为最小节点肯定没有左子节点,所以意味着,最小节点有一个或者没有子节点 图中18节点
2、如果要删除的节点没有子节点,只需要将父节点中,指向要删除节点的指针置为null即可 图中55节点
3、如果要删除的节点只有一个子节点,只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了 图中13节点
删除操作示意图

二叉查找树一个重要特性,就是中序遍历二叉查找树,可以输出有序数列,时间复杂度是O(n),因此二叉查找树又叫做二叉排序树
如果二叉查找树中存在两个相同对象,解决方法有两种:
1、二插查找树中每一个节点不仅会存储一个数据,可以通过链表和支持动态扩容的数组等数据结构,把值相同的数据都存储在同一个点上
2、每个节点仍然只存储一个数据,在查找插入位置的过程中,如果碰到一个节点值,与要插入数据的值相同,就将这个要插入的数据放到这个节点的右子树,吧这个插入的新值当做大于这个节点的值来处理;当要查找数据的时候,遇到值相同的节点,并不停止查找操作,而是继续在右子树中查找,直到遇到叶子节点,才停止。这样就可以把键值等于要查找值的所有节点都找出来
二叉查找树存储相同值的查找操作示意图
对于删除操作,需要先查到每个要删除的节点,然后再按前面讲的删除操作方法,依次删除
二叉查找树的时间复杂度分析
二叉查找树形态各式各样,查找、插入、删除操作的执行效率都是不一样的。根节点左右子树极度不平衡,极端情况会变成链表,查找的时间复杂度就变成了O(n)
当二叉查找树是一个完全二叉树或者满二叉树,所有操作均和树的高度成正比,通过等比数列求和公式,完全二叉树的高度小于等于log2n

二叉树相较于散列表的优势
1、散列表的数据是无序存储的,如果要有序输出,需要先进行排序。对于二叉查找树,只要中序遍历,就可以在O(n)的时间复杂度,输出有序数据序列
2、散列表扩容耗时多,遇到散列冲突,性能不稳定,常用的平衡二叉查找树性能稳定,时间复杂度为O(logn)
3、由于散列表存在哈希冲突,操作时间复杂度虽然是常量级,但不一定比logn小。再加上哈希函数耗时,散列表不一定比平衡二叉查找树效率高
4、散列表需要考虑散列函数设计、冲突解决方法、扩容、缩容等,平衡二叉查找树只需要考虑平衡性
5、为了避免过多的散列冲突,散列表装载因子不能太大,浪费存储空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值