删除节点是二叉树中最复杂的一部分,所以放在此处单独说明。
基本思路:
1. 首先,在删除之前我们需要查找到需要删除的节点。这一点可以借鉴find()方法。
2. 找到之后,我们需要了解该如何删除此节点。首先我们知道,要删除的节点可能出现的情况有三种:
①该节点是叶子节点,即没有子节点。
那么要删除它,自然可以直接删除啦,只需要改变父节点的引用值就行,即将指向该节点的引用设置为null
②该节点有一个子节点
那么要改变父节点的引用,将父节点的引用设置成要删除节点的子节点
③该节点有两个子节点
这种情况要考虑的情况最为复杂。若要删除此类节点,则需要使用它的中序后继来替代该节点。
其中,中序后继指的是:比该节点大,但是是数值最为接近该节点的节点,这个节点即为中序后继。
下面给出删除节点的方法以及寻找中序后继的方法:
/** * 删除节点 * @param data */ public void delete(int data) { //引用当前节点,从根节点开始 Node current = root; //引用当前节点的父节点 Node parent = root; //是否为左孩子 boolean isLeftChild = true; //先找到该节点 while(current.data != data) { parent = current; //进行比较,比较查找值和当前节点的大小 if(current.data>data) { current = parent.leftChild; isLeftChild = true; } else { current = parent.rightChild; isLeftChild = false; } //若树中无要删除的节点 if(current == null) { System.out.println("对不起,未查找到要删除的节点!"); return; } } //删除节点 //1.若该节点是叶子节点,即没有孩子 if(current.leftChild == null && current.rightChild == null) { //注意!记得考虑要删除节点为root的情况 if(current == this.root) { this.root = null; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); return; } //如果要删除的节点是父节点的左孩子 if(isLeftChild) parent.leftChild = null; else parent.rightChild = null; //如果要删除的节点是父节点的左孩子 System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); return; } else if(current.rightChild == null) {// 若要删除的节点只要一个左孩子 //注意!记得考虑要删除节点为root的情况 if(current == this.root) { this.root = current.leftChild; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); return; } if(isLeftChild) parent.leftChild = current.leftChild; else parent.rightChild = current.leftChild; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); } else if(current.leftChild == null) {//若要删除的节点只有一个右孩子 //注意!记得考虑要删除节点为root的情况 if(current == this.root) { this.root = current.rightChild; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); return; } if(isLeftChild) parent.leftChild = current.rightChild; else parent.rightChild = current.rightChild; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功!"); } else { //最后一种情况,即要删除节点有两个孩子 Node successor = getSuccessor(current); if(current == root) { this.root = successor; } else if(isLeftChild) { // 若要删除节点是一个左子节点 parent.leftChild = successor; } else { parent.rightChild = successor; } successor.leftChild = current.leftChild; System.out.println("要删除的数据: " + current.data + ", " + current.sdata); System.out.println("删除成功"); } } /** * 用来寻找中序后继节点 * @param delNode * @return 返回中序后继节点 */ public Node getSuccessor(Node delNode) { //先建立一个引用 Node successor = delNode; //建立一个父节点 Node successorParent = delNode; //这里因为是循环中序后继,所以是从要删除节点的右子树开始寻找 Node current = delNode.rightChild; //假设要删除节点为P,P的右孩子为P1,则中序后继只可能存在于P1的左子树上或者是P1本身 while(current != null) { successorParent = successor; successor = current; current = current.leftChild; } if(successor != delNode.rightChild) { successorParent.leftChild = successor.rightChild; successor.rightChild = delNode.rightChild; } return successor; }