Java实现链式存储的二叉查找树(递归方法),程序员面试宝典

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

}

}

}

return node;

}

//二叉查找树的中序遍历,可以得到一个递增的有序数列

public void inOrder(TreeNode node){

if(node != null){

inOrder(node.getLchild());

System.out.print(node.getData()+" ");

inOrder(node.getRchild());

}

}

//二叉查找树的层次遍历

public void levelOrder(TreeNode root){

Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();

TreeNode node = null;

nodeQueue.add(root); //将根节点入队

while(!nodeQueue.isEmpty()){ //队列不空循环

node = nodeQueue.peek();

System.out.print(node.getData()+" ");

nodeQueue.poll(); //队头元素出队

if(node.getLchild() != null){ //左子树不空,则左子树入队列

nodeQueue.add(node.getLchild());

}

if(node.getRchild() != null){ //右子树不空,则右子树入队列

nodeQueue.add(node.getRchild());

}

}

}

//查找数据域为data的结点,若不存在,返回null

public TreeNode searchNode(TreeNode node, Integer data){

while(node != null && node.getData() != data){

if(node.getData() > data){

node = node.getLchild(); //根节点>数据,向左走

}else{

node = node.getRchild(); //根节点<数据,向右走

}

}

return node;

}

//查找最大值:不断地寻找右子节点

public TreeNode getMaxData(TreeNode node){

if(node.getRchild() == null){

return node;

}else{

return getMaxData(node.getRchild());

}

}

//查找最小值:不断地寻找左子节点

public TreeNode getMinData(TreeNode node){

if(node.getLchild() == null){

return node;

}else{

return getMinData(node.getLchild());

}

}

//得到数据域为data的结点的直接父节点parentNode

public TreeNode getParentNode(TreeNode root, Integer data){

TreeNode parentNode = root;

if(parentNode.getData() == data){ //根节点的父节点返回为null

return null;

}

while(parentNode != null){

//查找当前节点的父节点的左右子节点,若是相等,则返回该父节点

if((parentNode.getLchild() != null && parentNode.getLchild().getData() == data) ||

(parentNode.getRchild() != null && parentNode.getRchild().getData() == data)){

return parentNode;

}else{

if(parentNode.getData() > data){ //向左查找父节点

parentNode = parentNode.getLchild();

}else{

parentNode = parentNode.getRchild(); //向右查找父节点

}

}

}

return null;

}

/**

  • 得到结点node的直接前趋

  • a.该节点左子树不为空:其前驱节点为其左子树的最大元素

  • b.该节点左子树为空: 其前驱节点为其祖先节点(递归),且该祖先节点的右孩子也为其祖先节点

  • (就是一直往其parent找,出现左拐后的那个祖先节点)

*/

public TreeNode getPrecessor(TreeNode root,TreeNode node){

if(node == null){

return null;

}

//a.该节点左子树不为空:其前驱节点为其左子树的最大元素

if(node.getLchild() != null){

return getMaxData(node.getLchild());

}else{ //b.该节点左子树为空: 其前驱节点为其祖先节点(递归)

TreeNode parentNode = getParentNode(root, node.getData());

while(parentNode != null && node == parentNode.getLchild()){

node = parentNode;

parentNode = getParentNode(root, parentNode.getData());

}

return parentNode;

}

}

/**

  • 得到结点node的直接后继(后继节点就是比要删除的节点的关键值要大的节点集合中的最小值)

  • a.该节点右子树不为空,其后继节点为其右子树的最小元素

  • b.该节点右子树为空,则其后继节点为其祖先节点(递归),且此祖先节点的左孩子也是该节点的祖先节点,

  • 就是说一直往上找其祖先节点,直到出现右拐后的那个祖先节点:

*/

public TreeNode getSuccessor(TreeNode root,TreeNode node){

if(node == null){

return null;

}

//a.该节点右子树不为空,其后继节点为其右子树的最小元素

if(node.getRchild() != null){

return getMinData(node.getRchild());

}else{ //b.该节点右子树为空,则其后继节点为其最高祖先节点(递归)

TreeNode parentNode = getParentNode(root, node.getData());

while(parentNode != null && node == parentNode.getRchild()){

node = parentNode;

parentNode = getParentNode(root, parentNode.getData());

}

return parentNode;

}

}

/**

  • 删除数据域为data的结点

  • 按三种情况处理:

  • a.如果被删除结点z是叶子节点,则直接删除,不会破坏二叉查找树的性质

  • b.如果节点z只有一颗左子树或右子树,则让z的子树成为z父节点的子树,代替z的位置

  • c.若结点z有左、右两颗子树,则令z的直接后继(或直接前驱)替代z,

  • 然后从二叉查找树中删去这个直接后继(或直接前驱),这样就转换为第一或第二种情况

  • @param node 二叉查找树的根节点

  • @param data 需要删除的结点的数据域

  • @return

*/

public boolean deleteNode(TreeNode node, Integer data){

if(node == null){ //树为空

throw new RuntimeException(“树为空!”);

}

TreeNode delNode= searchNode(node, data); //搜索需要删除的结点

TreeNode parent = null;

if(delNode == null){ //如果树中不存在要删除的关键字

throw new RuntimeException(“树中不存在要删除的关键字!”);

}else{

parent = getParentNode(node,data); //得到删除节点的直接父节点

//a.如果被删除结点z是叶子节点,则直接删除,不会破坏二叉查找树的性质

if(delNode.getLchild()==null && delNode.getRchild()==null){

if(delNode==parent.getLchild()){ //被删除节点为其父节点的左孩子

parent.setLchild(null);

}else{ //被删除节点为其父节点的右孩子

parent.setRchild(null);

}

return true;

}

//b1.如果节点z只有一颗左子树,则让z的子树成为z父节点的子树,代替z的位置

if(delNode.getLchild()!=null && delNode.getRchild()==null){

if(delNode==parent.getLchild()){ //被删除节点为其父节点的左孩子

parent.setLchild(delNode.getLchild());

}else{ //被删除节点为其父节点的右孩子

parent.setRchild(delNode.getLchild());

}

delNode.setLchild(null); //设置被删除结点的左孩子为null

return true;

}

//b2.如果节点z只有一颗右子树,则让z的子树成为z父节点的子树,代替z的位置

if(delNode.getLchild()==null && delNode.getRchild()!=null){

if(delNode==parent.getLchild()){ //被删除节点为其父节点的左孩子

parent.setLchild(delNode.getRchild());

}else{ //被删除节点为其父节点的右孩子

parent.setRchild(delNode.getRchild());

}

delNode.setRchild(null); //设置被删除结点的右孩子为null

return true;

}

//c.若结点z有左、右两颗子树,则删除该结点的后继结点,并用该后继结点取代该结点

if(delNode.getLchild()!=null && delNode.getRchild()!=null){

TreeNode successorNode = getSuccessor(node,delNode); //得到被删除结点的后继节点

deleteNode(node,successorNode.getData()); //删除该结点的后继结点

delNode.setData(successorNode.getData()); //用该后继结点取代该结点

return true;

}

}

return false;

}

public static void main(String args[]){

Scanner input = new Scanner(System.in);

Integer[] array = {8,3,10,1,6,14,4,7,13};

BinarySearchTree bst = new BinarySearchTree();

TreeNode root = bst.buildBST(array);

System.out.print(“层次遍历:”);

bst.levelOrder(root);

System.out.print(“\n”+“中序遍历:”);

bst.inOrder(root);

独家面经总结,超级精彩

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

image

image

image

image

Java面试准备

准确的说这里又分为两部分:

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

image

image

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

H5V282Lb-1713622577680)]

Java面试准备

准确的说这里又分为两部分:

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

[外链图片转存中…(img-gnn7kQ1S-1713622577680)]

[外链图片转存中…(img-vSx30mAw-1713622577681)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-ITE5wddh-1713622577682)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/** * 根据等级查询类目树 * * @param level * @return */ @Override public List queryCategoryTree(Integer level) { //查询当前级别下类目 List list = categoryDAO.list(level); //组装好的类目树,返回前端 List categoryTree = new ArrayList(); //所有类目 List allDTOList = new ArrayList(); if (CollectionUtils.isEmpty(list)) { return categoryTree; } for (CategoryDO categoryDO : list) { allDTOList.add(new CategoryTreeDTO().convertDOToDTO(categoryDO)); } //当前等级类目 categoryTree = allDTOList.stream().filter(dto -> level.equals(dto.getLevel())).collect(Collectors.toList()); for (CategoryTreeDTO categoryTreeDTO : categoryTree) { //组装类目为树结构 assembleTree(categoryTreeDTO, allDTOList,Constants.CATEGORY_MAX_LEVEL - level); } return categoryTree; } /** * 组装树 * * @param categoryTreeDTO * @param allList * @param remainRecursionCount 剩余递归次数 * @return */ public CategoryTreeDTO assembleTree(CategoryTreeDTO categoryTreeDTO, List allList, int remainRecursionCount) { remainRecursionCount--; //最大递归次数不超过Constants.CATEGORY_MAX_LEVEL-level次,防止坏数据死循环 if(remainRecursionCount < 0){ return categoryTreeDTO; } String categoryCode = categoryTreeDTO.getCategoryCode(); Integer level = categoryTreeDTO.getLevel(); //到达最后等级树返回 if (Constants.CATEGORY_MAX_LEVEL == level) { return categoryTreeDTO; } //子类目 List child = allList.stream().filter(a -> categoryCode.equals(a.getParentCode())).collect(Collectors.toList()); if (null == child) { return categoryTreeDTO; } categoryTreeDTO.setChildren(child); //组装子类目 for (CategoryTreeDTO dto : child) { assembleTree(dto, allList,remainRecursionCount); } return categoryTreeDTO; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值