Java最新腾讯大牛教你如何使用Java实现二叉树的添加,删除,获取以及遍历,查漏补缺

架构学习资料

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

return t;

}

return null;

}

/**

  • 查找后继节点

  • @param delEntry 删除节点

  • @return 后继节点

*/

private Entry successor(Entry delEntry) {

Entry r = delEntry.right;//r节点必定不为空

while (r.left != null){

r = r.left;

}

return r;

}

二叉树获取节点

/**

  • 判断是否存在该元素

  • @param item 查找元素

  • @return 结果

*/

public boolean contains(T item){

return getEntry(item) != null;

}

/**

  • 获取节点节点

  • @param item 获取节点

  • @return 获取到的节点,可能为null

*/

private Entry getEntry(T item){

Entry t = root;

int ret;

//从根节点开始遍历

for (;t != null;){

ret = item.compareTo(t.item);

if (ret < 0)

t = t.left;

else if (ret > 0)

t = t.right;

else

return t;

}

return null;

}

因为我这个例子是存储一个元素,获取到的元素和传进去的元素是一致的,所以我用contains方法来判断返回true即表示获取成功了,不返回获取到的结果了。当然,如果将entry存储的元素改为kv形式的话,就可以使用get方法了。

二叉树的遍历

======

二叉树的遍历可以分为三种:前序遍历、中序遍历和后续遍历,其中中序遍历是最常用的遍历方式,因为它遍历出来的结果的升序的。

前序遍历

/**

  • 前序遍历

  • @param e 开始遍历元素

*/

public void prevIterator(Entry e){

if (e != null) {

System.out.print(e.item + " ");

prevIterator(e.left);

prevIterator(e.right);

}

}

中序遍历

/**

  • 中序遍历

  • @param e

*/

public void midIterator(Entry e){

if (e != null){

midIterator(e.left);

System.out.print(e.item + " ");

midIterator(e.right);

}

}

后序遍历

/**

  • 后续遍历

  • @param e 开始遍历元素

*/

public void subIterator(Entry e){

if (e != null) {

subIterator(e.left);

subIterator(e.right);

System.out.print(e.item + " ");

}

}

package com.rainple.collections;

/**

  • 二叉树

  • @param

*/

public class BinaryTree<T extends Comparable> {

//根节点

private Entry root;

//数据量

private int size = 0;

public BinaryTree(){}

/**

  • 添加元素

  • @param item 待添加元素

  • @return 已添加元素

*/

public T put(T item){

//每次添加数据的时候都是从根节点向下遍历

Entry t = root;

size++;

if (t == null){

//当前的叉树树的为空,将新节点设置为根节点,父节点为null

root = new Entry<>(item,null);

return root.item;

}

//自然排序结果,如果传入的数据小于当前节点返回-1,大于当前节点返回1,否则返回0

int ret = 0;

//记录父节点

Entry p = t;

while (t != null){

//与当前节点比较

ret = item.compareTo(t.item);

p = t;

//插入节点比当前节点小,把当前节点设置为左子节点,然后与左子比较,以此类推找到合适的位置

if (ret < 0)

t = t.left;

//大于当前节点

else if (ret > 0)

t = t.right;

else {

//相等就把旧值覆盖掉

t.item = item;

return t.item;

}

}

//创建新节点

Entry e = new Entry<>(item,p);

//根据比较结果将新节点放入合适的位置

if (ret < 0)

p.left = e;

else

p.right = e;

return e.item;

}

public void print(){

midIterator(root);

}

/**

  • 中序遍历

  • @param e

*/

public void midIterator(Entry e){

if (e != null){

midIterator(e.left);

System.out.print(e.item + " ");

midIterator(e.right);

}

}

/**

  • 获取根节点

  • @return 根节点

*/

public Entry getRoot(){return root;}

/**

  • 前序遍历

  • @param e 开始遍历元素

*/

public void prevIterator(Entry e){

if (e != null) {

System.out.print(e.item + " ");

prevIterator(e.left);

prevIterator(e.right);

}

}

/**

  • 后续遍历

  • @param e 开始遍历元素

*/

public void subIterator(Entry e){

if (e != null) {

subIterator(e.left);

subIterator(e.right);

System.out.print(e.item + " ");

}

}

/**

  • 获取节点节点

  • @param item 获取节点

  • @return 获取到的节点,可能为null

*/

private Entry getEntry(T item){

Entry t = root;

int ret;

//从根节点开始遍历

for (;t != null;){

ret = item.compareTo(t.item);

if (ret < 0)

t = t.left;

else if (ret > 0)

t = t.right;

else

return t;

}

return null;

}

/**

  • 判断是否存在该元素

  • @param item 查找元素

  • @return 结果

*/

public boolean contains(T item){

return getEntry(item) != null;

}

/**

  • 删除元素

  • 删除元素如果细分的话,可以分为4中:没有子节点,只有左节点,只有右节点,有两个子节点

  • 1)没有子节点这种情况比较简单,直接删除就可以了

  • 2)只有左节点或右节点,这两种情况处理方式是一致的,只是方向相反,所以在一起讲了,

  • 将删除节点的父节点的左节点(右节点)指向删除节点的子节点,将左节点(右节点)指向删除节点的父节点

  • 3)有两个子节点,这种情况相对来说比较复杂一点:

  • 找到删除节点的前驱节点或后继节点,然后将前驱或后继节点的值赋给删除节点,然后将前驱或后继节点删除。本质是删除前驱或后继节点

  • 前驱节点的特点:

  • 1)删除的左子节点没有右子节点,那么左子节点即为前驱节点

  • 2)删除节点的左子节点有右子节点,那么最右边的最后一个节点即为前驱节点

  • 后继节点的特点:

  • 与前驱节点刚好相反,总是右子节点,或则右子节点的最左子节点;例如:删除节点为c ,那么前驱节点为 m,后继节点为n

  •                                      a
    
  •                                   /     \
    
  •                                b          c
    
  •                              / \         /  \
    
  •                            d    e       f    g
    
  •                          /  \  / \     / \   / \
    
  • @param item 删除元素 h i j k l m n o

  • @return 删除结果

*/

public boolean remove(T item){

//获取删除节点

Entry delEntry = getEntry(item);

if (delEntry == null) return false;

//删除节点的父节点

Entry p = delEntry.parent;

size–;

//情况1:没有子节点

if (delEntry.left == null && delEntry.right == null){

//删除节点为根节点

if (delEntry == root){

root = null;

}else {//非根节点

//删除的是父节点的左节点

if (delEntry == p.left){

p.left = null;

}else {//删除右节点

p.right = null;

}

}

//情况2:删除的节点只有左节点

}else if (delEntry.right == null){

Entry lc = delEntry.left;

//删除的节点为根节点,将删除节点的左节点设置成根节点

if (p == null) {

lc.parent = null;

root = lc;

} else {//非根节点

if (delEntry == p.left){//删除左节点

p.left = lc;

}else {//删除右节点

p.right = lc;

}

lc.parent = p;

}

//情况3:删除节点只有右节点

}else if (delEntry.left == null){

Entry rc = delEntry.right;

//删除根节点

if (p == null) {

rc.parent = null;

root = rc;

}else {//删除非根节点

if (delEntry == p.left)

p.left = rc;

else

p.right = rc;

rc.parent = p;

}

//情况4:删除节点有两个子节点

}else {//有两个节点,找到后继节点,将值赋给删除节点,然后将后继节点删除掉即可

Entry successor = successor(delEntry);//获取到后继节点

delEntry.item = successor.item;

//后继节点为右子节点

if (delEntry.right == successor){

//右子节点有右子节点

if (successor.right != null) {

delEntry.right = successor.right;

successor.right.parent = delEntry;

}else {//右子节点没有子节点

delEntry.right = null;

}

}else {//后继节点必定是左节点

successor.parent.left = null;

}

return true;

}

//让gc回收

delEntry.parent = null;

delEntry.left = null;

delEntry.right = null;

return true;

}

/**

  • 查找后继节点

  • @param delEntry 删除节点

  • @return 后继节点

*/

private Entry successor(Entry delEntry) {

Entry r = delEntry.right;//r节点必定不为空

while (r.left != null){

r = r.left;

}

return r;

}

public int size(){return size;}

public boolean isEmpty(){return size == 0;}

public void clear(){

clear(getRoot());

root = null;

}

private void clear(Entry e){

if (e != null){

clear(e.left);

e.left = null;

clear(e.right);

e.right = null;

}

}

static final class Entry<T extends Comparable>{

//保存的数据

private T item;

//左子树

private Entry left;

//右子树

private Entry right;

//父节点

private Entry parent;

Entry(T item,Entry parent){

this.item = item;

this.parent = parent;

}

}

}

测试代码示例

《MySql面试专题》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

《MySql性能优化的21个最佳实践》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

《MySQL高级知识笔记》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

文中展示的资料包括:**《MySql思维导图》《MySql核心笔记》《MySql调优笔记》《MySql面试专题》《MySql性能优化的21个最佳实践》《MySq高级知识笔记》**如下图

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

关注我,点赞本文给更多有需要的人

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

《MySQL高级知识笔记》

[外链图片转存中…(img-5yLd1MT9-1715442772538)]

[外链图片转存中…(img-Ks03K6Jr-1715442772538)]

[外链图片转存中…(img-c2KZSy8M-1715442772539)]

[外链图片转存中…(img-wgSBmI26-1715442772539)]

[外链图片转存中…(img-0BE7n3dZ-1715442772539)]

[外链图片转存中…(img-rWUshiKK-1715442772540)]

[外链图片转存中…(img-Iv9tc0ip-1715442772540)]

[外链图片转存中…(img-dpFHdm8j-1715442772540)]

[外链图片转存中…(img-yCyRWaeT-1715442772540)]

[外链图片转存中…(img-daMTGAJV-1715442772541)]

文中展示的资料包括:**《MySql思维导图》《MySql核心笔记》《MySql调优笔记》《MySql面试专题》《MySql性能优化的21个最佳实践》《MySq高级知识笔记》**如下图

[外链图片转存中…(img-96h5Mz8i-1715442772541)]

关注我,点赞本文给更多有需要的人

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值