java实现二叉搜索树的非递归方式删除

java实现二叉搜索树的删除(非递归方式)

网上有很多的二叉搜索树的java实现都是基于递归的,非递归看了半天好多都是一模一样的,并且好多都有问题,下面就是我在网上看到的最多的错误版本:

public void deleteMin(Node node){ //删除该节点下的最小节点
        Node currentNode=node;
        Node parentNode=node;
        if(currentNode==null)
            return;
        //先定位到key,不用已经写好的find方法而自己写是因为find方法是从根开始的,有些地方的用到这个函数不用从根开始
        //一直往左深入,直到它的左子节点为null,然后将其右子节点替换掉该节点(如无右节点即为null)。
        while(currentNode.left!=null){
 
            parentNode=currentNode;
            currentNode=currentNode.left;
        }
        parentNode.left=currentNode.right; 
        currentNode.right=null;
 
    }

此处错误就是并没有考虑删除节点是根节点的情况,如待删除的树没有左节点和右节点,此时,按照上面代码的逻辑,并不会进入while循环,currentNode = parentNode,currentNode并没有被删除,所以用这种方式删除是不能完全删除的。下面时改进的代码

	public E removeMin() {
        E res = getMin(root).e;
        root = removeMin(root);
        return res;
    }
    private Node<E> removeMin(Node<E> cur) {
        Node<E> resCur = cur;       //临时保存cur的值,将修改后的值返回回去
        Node<E> p = cur;            //cur的父节点
        if (cur == null) {
            throw new NoSuchElementException();
        } else if (cur.left == null) {  //当没有左节点时,最小值就是自己(cur)
            Node<E> res = cur.right;    //创建节点返回cur的右节点,将自己删除
            size--;
            return res;
        }
        while (cur.left != null) {
            p = cur;
            cur = cur.left;
        }
        p.left = cur.right;
        cur.right = null;
        size--;
        return resCur;
    }

解决办法是在while循环前加if判断当前节点是否为最小节点,起初,我是想让cur = cur.right将根节点删除的,可是发现这样删除cur的根节点引用并不会消失,也怪自己对对象的引用没有太深刻的理解。受递归代码的实现的启发,将删除节点后的树赋值给新创建的节点res,返回给删除之前的树,这样就可以成功删除掉了。删除最大值也是一样的。由于本人第一次写博客,可能表达不是太清晰,望理解。下面时二叉搜索树的全部实现,本人能力有限,如果有错误的地方欢迎指正。(总感觉自己写的代码有很大的优化空间,欢迎指出,谢谢)

package tree;

import basic.Stack;

import java.util.Comparator;
import java.util.NoSuchElementException;

/**
 * @author yqs
 * @description 二叉搜索树
 * define 左子树比根节点小,右子树比根节点大
 * @time 19-7-23 下午7:26
 */
public class BinarySearchTree<E extends Comparable<E>> {
    private int size;
    private Node<E> root;
    public BinarySearchTree(){
        root = new Node<>();
        size = 0;
    }

    private class Node<E> {
        private Node<E> left;
        private Node<E> right;
        private E e;
        public Node() {}

        public Node(Node<E> left, E e, Node<E> right) {
            this.left = left;
            this.e = e;
            this.right = right;
        }
    }

    public boolean add(E e) {
        if (size == 0) {
            root = new Node<>(null,e,null);
            size++;
            return true;
        }
        Node<E> cur = root;
        Node<E> p = cur;
        while (cur != null) {
            p = cur;
            if (e.compareTo(cur.e) < 0)
                cur = cur.left;
            else if (e.compareTo(cur.e) > 0)
                cur = cur.right;
            else
                return false;
        }
        if (p.e.compareTo(e) > 0)
            p.left = new Node<>(null,e,null);
        else
            p.right = new Node<>(null,e,null);
        size++;
        return true;
    }
    //删除节点
    public void remove(E e){
        root = remove(root, e);
    }

    private Node<E> remove(Node root,E e) {
        Node<E> resCur = root;
        Node<E> cur = root;
        Node<E> p = cur;
        if (root == null)
            throw new NoSuchElementException();
        while (cur != null) {
            if (e.compareTo(cur.e) < 0) {
                p = cur;
                cur = cur.left;
            } else if (e.compareTo(cur.e) > 0) {
                p = cur;
                cur = cur.right;
            } else {    //找到节点,cur为待删除节点,p为cur父节点
                if (p == cur) {     //此时要删除的为根节点
                    if (cur.right != null) {    //判断根节点有没有右节点
                        Node<E> newRoot = new Node<E>(null, getMin(cur.right).e,null);
                        newRoot.left = cur.left;
                        newRoot.right = removeMin(cur.right);
                        return newRoot;
                    }else {
                        Node<E> newRoot = cur.left;
                        size--;
                        return newRoot;
                    }
                }
                //待删除节点左右节点都不为空,4种情况
                if (cur.right != null && cur.left != null) {
                    Node<E> newRoot = new Node<E>(null, getMin(cur.right).e,null);
                    newRoot.left = cur.left;
                    newRoot.right = removeMin(cur.right);
                    if (p.e.compareTo(newRoot.e) > 0) {
                        p.left = newRoot;
                    }else {
                        p.right = newRoot;
                    }
                    return resCur;
                } else if (cur.left != null && cur.right == null) {
                    if (p.e.compareTo(cur.e) > 0) {
                        p.left = cur.left;
                    }else {
                        p.right = cur.left;
                    }
                } else if (cur.left == null && cur.right != null) {
                    if (p.e.compareTo(cur.e) > 0) {
                        p.left = cur.right;
                    }else {
                        p.right = cur.right;
                    }
                } else {
                    if (p.e.compareTo(cur.e) > 0) {
                        p.left = null;
                    }else {
                        p.right = null;
                    }
                }
                size--;
                return resCur;
            }
        }
        return resCur;
    }
    public E removeMin() {
        E res = getMin(root).e;
        root = removeMin(root);
        return res;
    }
    public E removeMax() {
        E res = getMax(root).e;
        root = removeMax(root);
        return res;
    }

    private Node<E> removeMin(Node<E> cur) {
        Node<E> resCur = cur;       //临时保存cur的值,将修改后的值返回回去
        Node<E> p = cur;            //cur的父节点
        if (cur == null) {
            throw new NoSuchElementException();
        } else if (cur.left == null) {  //当没有左节点时,最小值就是自己(cur)
            Node<E> res = cur.right;    //创建节点返回cur的右节点,将自己删除
            size--;
            return res;
        }
        while (cur.left != null) {
            p = cur;
            cur = cur.left;
        }
        p.left = cur.right;
        cur.right = null;
        size--;
        return resCur;
    }
    private Node<E> removeMax(Node<E> cur) {
        Node<E> resCur = cur;
        Node<E> p = cur;
        if (cur == null) {
            throw new NoSuchElementException();
        } else if (cur.right == null) {  //当最小值就是自己的时候
            Node<E> res = cur.left;
            size--;
            return res;
        }
        while (cur.right != null) {
            p = cur;
            cur = cur.right;
        }
        p.right = cur.left;
        cur.left = null;
        size--;
        return resCur;
    }
    private Node<E> getMin(Node cur) {
        Node<E> p = cur;
        while (cur != null) {
            p = cur;
            cur = cur.left;
        }
        return p;
    }
    private Node<E> getMax(Node cur) {
        Node<E> p = cur;
        while (cur != null) {
            p = cur;
            cur = cur.right;
        }
        return p;
    }

    public int getSize() {
        return size;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        traverse(sb, root);
        return sb.toString();
    }

    public void traverse(StringBuilder sb,Node<E> root) {
        if (root == null)
            return;
        Stack<Node> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                sb.append(root.e+",");      //前序遍历
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            //sb.append(root.e+",");      //中序遍历
            root = root.right;
        }
    }
}

代码写的有点乱,还有很大的优化空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值