二叉树删除节点

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

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. centos rpm安装mysql5.5_CentOS 5.5下RPM方式安装MySQL 5.5 详解
  2. ajax传递参数给springmvc总结[转]
  3. Why AG3 client 815 transport entries disabled
  4. zookeeper zoo.cfg配置文件
  5. linux C语言多线程库pthread中条件变量的正确用法逐步详解
  6. 动态链接库实现COM(COM技术内幕笔记之二)
  7. Java版 18w10c_xcvbn.apk 0% 的杀毒软件(0/32) 报告发现病毒 - VirSCAN.org-多引擎在线病毒扫描网 v1.02,当前支持 47 款杀毒引擎...
  8. static{}语句块详解
  9. 线性表_使用栈实现二进制转换到八进制/十进制/十六进制
  10. template.js 模板引擎
  11. c# 正则表达式对网页进行有效内容抽取
  12. 高级商务办公软件应用【5】
  13. 各类文件的文件头标志
  14. 东南大学女孩子学计算机的多吗,2019年应届南邮上岸东南大学计算机生,经验分享,希望能帮助到迷茫的你...
  15. ironman钢铁侠高清mac动态壁纸
  16. 【Serenity BDD】Serenity 2.2.0 版本变动说明及相应的配置变动
  17. SAS硬盘和SATA硬盘傻傻分不清?不懂的看这里
  18. Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六)
  19. 一个已经转行一年的程序员的感受
  20. 敏捷开发 宣言 思想 认识误区

热门文章

  1. 数字油田AI平台建设之视野、策略及切入点(深度好文)
  2. redux启示与实践
  3. 邱淑贞的女儿太漂亮啦,邱淑贞为她女儿站台!
  4. DNS污染——domain name的解析被劫持了返回无效的ip
  5. 2021长安二中高考成绩查询,2020年陕西高考成绩已公布,速看
  6. ros基础概念以及第一个项目
  7. 资深猎头眼中的优质简历是如何炼成的?
  8. 每日一句英语 2012-9-15
  9. 常用页面代码html
  10. 无域名HTTP请求攻击分析