二叉树删除节点

在自己研究二叉树删除节点时,查网上资料时发现,网上大部分写的都是错的,主要错在当删除的节点既存在左子树,又存在右子树时,在中序遍历后获取后继节点后,大部分文章未考虑后继节点存在右子树的情况。

1.二叉树图


删除的节点有4种情况

  1. 叶子节点
  2. 只存在左节点
  3. 只存在右节点
  4. 既存在左节点,又存在右节点

以上四种情况分别如下处理:

1只需要将引用去除就行
2将删除节点的左子树,挂到父节点上
3将删除节点的右子树,挂到父节点上
4中序遍历树,获取删除节点的后继节点,即大于删除节点的最小节点,后继节点可以确定的是肯定不存在左子树,因为后继节点就是删除节点右子树里面最小的节点了,肯定不存在比他还小的节点。但是还是有可能存在右子树的 。处理逻辑就是将后继节点的值覆盖删除节点的值,并将后继节点的右子树挂到后继节点的父节点上。

下面就是硬干代码了,有个技巧,中序遍历出来的结果正好是升序排列的树,所以在删除后,可以通过打印中序遍历的结果,查看整棵树是不是正确的。

2.节点数据结构

public static class Node<T>{private T data;private Node<T> left;private Node<T> right;private Node<T> parent;public Node(T data) {this.data = data;}public T getData() {return data;}public Node<T> getParent() {return parent;}public void setParent(Node<T> parent) {this.parent = parent;}public void setData(T data) {this.data = data;}public Node<T> getLeft() {return left;}public void setLeft(Node<T> left) {this.left = left;}public Node<T> getRight() {return right;}public void setRight(Node<T> right) {this.right = right;}}

3.先序创建树

// 创建树
public static Node<String> createTree(List<String> dataList,Node<String> parent){Node<String> root = null;if(!dataList.isEmpty()){String data = dataList.remove(0);if(data!=null){root=new Node<>(data);root.setParent(parent);root.setLeft(createTree(dataList,root));root.setRight(createTree(dataList,root));}}return root;}//二叉树初始化List<String> strings = new ArrayList<>();strings.add("20");strings.add("7");strings.add("3");strings.add("2");strings.add(null);strings.add(null);strings.add("4");strings.add(null);strings.add(null);strings.add("10");strings.add("8");strings.add(null);strings.add("9");strings.add(null);strings.add(null);strings.add("12");strings.add(null);strings.add(null);strings.add("30");strings.add("25");strings.add(null);strings.add("26");strings.add(null);strings.add(null);strings.add("35");strings.add(null);strings.add(null);tree = createTree(strings,null);

4.删除操作

// 删除节点
public static String deleteNode(Node<String> tree,String value){//找到指定节点Node<String> deleteNode = findNode(tree, value);//节点不存在直接返回if(deleteNode==null){return null;}//原值String result = deleteNode.getData();//判断子节点情况//及存在左子树又存在右子树if(deleteNode.getLeft()!=null && deleteNode.getRight()!=null){//对整个树中序遍历,以获取删除节点的后继节点(大于删除节点的最小节点)Node<String> afterNode = findAfterNode(tree, deleteNode);//删除节点与后继节点值替换deleteNode.setData(afterNode.getData());//当前节点一定不存在左子树,有可能存在右子树if(afterNode.getRight()==null){//当不存在右子数时,直接跟删除节点交换deleteNode.setData(afterNode.getData());//将对后继节点的引用置空Node<String> parent = afterNode.getParent();if(parent.getLeft()==afterNode){parent.setLeft(null);}else{parent.setRight(null);}afterNode.setParent(null);}else{//当存在右子树时,将右子数挂在后继节点的父节点下Node<String> parent = afterNode.getParent();if(parent.getLeft()==afterNode){parent.setLeft(afterNode.getRight());}else{parent.setRight(afterNode.getRight());}afterNode.getRight().setParent(parent);}}else if(deleteNode.getLeft()!=null && deleteNode.getRight()==null){//只存在左子树//父节点指向左子树Node<String> parent = deleteNode.getParent();if(parent.getLeft()==deleteNode){parent.setLeft(deleteNode.getLeft());}else{parent.setRight(deleteNode.getLeft());}afterNode.getLeft().setParent(parent);afterNode.setParent(null);}else if(deleteNode.getLeft()==null && deleteNode.getRight()!=null){//只存在右子树Node<String> parent = deleteNode.getParent();if(parent.getLeft()==deleteNode){parent.setLeft(deleteNode.getRight());}else{parent.setRight(deleteNode.getRight());}afterNode.getRight().setParent(parent);afterNode.setParent(null);}else{//叶子节点//将指向该节点父节点置空Node<String> parent = deleteNode.getParent();if(parent.getLeft()==deleteNode){parent.setLeft(null);}else{parent.setRight(null);}afterNode.setParent(null);}return result;}
//节点查询
public static <A extends String> Node<A> findNode(Node<A> root,A value){if(root ==null){return null;}Node<A> cnode = root;while(cnode!=null){if(value.compareTo(cnode.getData())==0){return cnode;}if(Integer.parseInt(value)<Integer.parseInt(cnode.getData())){cnode=cnode.left;continue;}if(Integer.parseInt(value)>Integer.parseInt(cnode.getData())){cnode=cnode.right;continue;}}return null;}
// 找到指定节点的后继节点
public static Node<String> findAfterNode(Node<String> root,Node<String> targetNode){ArrayList<Node<String>> list = new ArrayList<>();midSercharStack(root,list);for (int i = 0; i < list.size(); i++) {if(Integer.valueOf(list.get(i).getData())==Integer.valueOf(targetNode.getData())){return list.get(++i);}}return null;}
//中序遍历树,并保存到列表中  public static void midSercharStack(Node<String> root, ArrayList<Node<String>> list){if(root==null){return;}midSercharStack(root.left,list);list.add(root);midSercharStack(root.right,list);}

5.中序遍历方法 递归+非递归


//非递归 中序遍历
public static void midPrintNoback(Node<String> root){LinkedList<Node<String>> stack = new LinkedList<>();Node<String> p = root;while(p!=null || !stack.isEmpty()){if(p!=null){stack.push(p);p=p.left;}else{Node<String> pop = stack.pop();System.out.println(pop.getData());p=pop.right;}}}//递归中序遍历
public static void midPrint(Node<String> root){if(root==null){return;}midPrint(root.getLeft());System.out.println(root.getData()==null?"":root.getData());midPrint(root.getRight());
}

6.测试

 public static void main(String[] args) {//先打印一遍树midPrint(tree);System.out.println("-------");//删除最复杂的 7节点String s = deleteNode(tree, "7");//打印删除后的树midPrint(tree);}

结果如下,可以发现,删除后,节点7已经不在了

7.附插入时,定位要插入的父节点

public static <A extends String> Node<A> findInsertNode(Node<A> root,A value){if(root ==null){return null;}Node<A> cnode = root;Node<A> pnode=null;while(cnode!=null){if(Integer.parseInt(value)<=Integer.parseInt(cnode.getData())){pnode=cnode;cnode=cnode.left;continue;}if(Integer.parseInt(value)>Integer.parseInt(cnode.getData())){pnode=cnode;cnode=cnode.right;continue;}}return pnode;
}

最完整二叉树删除节点相关推荐

  1. 二叉树删除节点以及前中后序遍历

    public class BinaryTreeDemo {public static void main(String args[]){Employee emp1= new Employee(1,&q ...

  2. 二叉树删除节点,(查找二叉树最大值节点)

    从根节点往下分别查找左子树和右子树的最大节点,再比较左子树,右子树,根节点的大小得到结果,在得到左子树和右子树最大节点的过程相似,因此可以采用递归的 //树节点结构 public class Tree ...

  3. 二叉树删除节点+思路分析

    思路分析 代码实现 ![在这里插入代码片](https://img-blog.csdnimg.cn/20210325193201194.png?x-oss-process=image/watermar ...

  4. C语言二叉树一个节点的所有祖先节点(附完整源码)

    C语言二叉树一个节点的所有祖先节点 一个节点的所有祖先节点 C语言二叉树一个节点的所有祖先节点完整源码(定义,实现,main函数测试) 一个节点的所有祖先节点 Given a binary Tree: ...

  5. 牛牛有一棵n个节点的二叉树,该二叉树每个节点的权值为1。牛牛想要删掉该树其中的k层节点,删除序列为a1,a2...ak。 如有一棵二叉树,删除其中的第3层节点

    题目:牛牛有一棵n个节点的二叉树,该二叉树每个节点的权值为1.牛牛想要删掉该树其中的k层节点,删除序列为a1,a2-ak. 如有一棵二叉树,删除其中的第3层节点 思路: 层序遍历,遍历时对节点依次进行 ...

  6. 二叉树C++ | 实现删除节点_4

    删除节点 /* Deleting a node from Binary search tree */ #include<iostream> using namespace std; str ...

  7. 二叉搜索树(BST)删除节点--思路清晰

    前言:在学习BST时,发现查找插入等操作都很好理解和实现,而删除节点的操作情况比较复杂,故通过自己的理解整理如下,本文适合初学者理解并自己动手实现BST删除操作. 在很多文章中提到,删除节点可以考虑以 ...

  8. 算法:二叉搜索树BST - 删除节点 详解(Java实现)

    删除节点 删除节点存在 3 种情况,几乎所有类似博客都提到了这点.这 3 种情况分别如下: 没有左右子节点,可以直接删除 存在左节点或者右节点,删除后需要对子节点移动 同时存在左右子节点,不能简单的删 ...

  9. 二十七、二叉树--删除结点

    一.删除规则 如果删除的节点是叶子节点,则删除该节点 如果删除的节点是非叶子节点,则删除该子树. 注意到时候学习二叉排序树的时候删除非叶子结点就不是这样了 二.删除结点思路分析 三.代码实现 pack ...

最新文章

  1. Efficiency / Relative Efficiency and the Efficient Estimator
  2. 自动添加端口添加至Windows防火墙脚本
  3. 《京东技术解密》读后感
  4. c++怎么实现数字数组的删除数字_C/C++数据结构:栈结构解析,最简单解析,让你一遍就会...
  5. kubernetes pv-controller 解析
  6. java 对象流传输socket_Java Socket(二)使用TCP传输对象
  7. [2014]Hiring Report of IT Company
  8. html title 不显示_SEO入门教程二:学习最基础的html代码知识
  9. nyoj 523 亡命逃窜 【BFS】
  10. Python基于OpenCV&YOLO台球击球路线规划系统(源码&部署教程)
  11. NRF52832 SDK 14.0.0设置内部32768
  12. 故障解决:发生系统错误 67 找不到网络名
  13. “前浪”微博财报里的悲喜两极
  14. 斑马打印机常见问题解决方案 条码打印机常见问题解决方案
  15. 白屏时间first paint 和可交互时间dom ready的关系
  16. 那些年,我们一起做过的 Java 课后练习题(26 - 30)
  17. 股票分时成交明细接口的数据怎么看?
  18. 理想低通滤波器(频率域滤波)
  19. 面试篇---大四实习面试经历,总结一下自己的面试过程(函渠道、面试题、面试经验)
  20. JVM自定义类加载器在代码扩展性的实践

热门文章

  1. #谷歌地图# 谷歌地图报错
  2. 如何用VBA快速批量提取多个工作表名称?
  3. 每天5分钟玩转Kubernetes | Cluster IP底层实现
  4. mac安装sql server
  5. 本站视频相关的C++新经典系列书籍出版
  6. 翻译考试用计算机作答,上半年CATTI考试方式还是纸笔,下半年就实行全面机考?真是几家欢喜几家愁!...
  7. 2019年 网络空间安全国赛真题 赛题分析
  8. 广西教师招聘需要计算机考试证,2020广西教师招聘报考需要有教师资格证吗
  9. linux 服务器的性能考核指标QPS、TPS、RT、Load、PV、UV
  10. 【项目经验】--环保项目