二分搜索树的实现(实现了前序、中序、后序遍历(递归、非递归两种方式)、添加元素、删除元素操作)【大家共同学习,有问题可以沟通交流】

import java.util.Queue;
import java.util.Stack;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 二分搜索树的实现
 * 
 * @author hcc
 *
 * @param <E>
 */
public class BST<E extends Comparable<E>> {
    private Node root;
    private int size;

    public BST() {
        this(null);
    }

    private BST(Node root) {
        this.root = root;
        this.size = 0;
    }

    /**
     * 添加元素
     * @param e
     */
    public void add(E e) {
        if (root == null) {
            root = new Node(e);
            size++;
        } else {
            add(this.root, e);
        }
    }
    
    /**
     * 添加元素的具体操作
     * @param root 树结构的根节点
     * @param e 将要添加的数据
     */
    private void add(Node root, E e) {
        // 也可以使用该表达式判断 e是否存在于树结构中
        // if(e.compareTo(root.data) == 0) {
        // return;
        // }
        if (e.equals(root.data)) {
            return;
        } else if (e.compareTo(root.data) < 0 && root.left == null) {
            Node node = new Node(e);
            root.left = node;
            size++;
        } else if (e.compareTo(root.data) > 0 && root.right == null) {
            Node node = new Node(e);
            root.right = node;
            size++;
        }

        if (e.compareTo(root.data) < 0) {
            add(root.left, e);
        }
        if (e.compareTo(root.data) > 0) {
            add(root.right, e);
        }
    }

    /**
     * 优化后的添加方法(优化了递归结束条件)
     */
    @SuppressWarnings("unused")
    private Node addForOptimize(Node root, E e) {
        if (root == null) {
            Node node = new Node(e);
            size++;
            return node;
        } else if (e.compareTo(root.data) < 0) {
            root.left = addForOptimize(root.left, e);
        } else if (e.compareTo(root.data) > 0) {
            root.right = addForOptimize(root.right, e);
        }
        return root;
    }

    /**
     * 删除操作,删除树中最小的元素、删除树中最大的元素、随意删除
     */
    /**
     * 删除“树”上最小的元素(在左下角,二分搜索树的性质决定的)
     * 
     * @return 返回该节点的值
     */
    public E removeMin() {
        Node node = removeMin(root);
        return node.data;
    }

    /**
     * 当找到左下角节点时,需判断该节点是否有“右孩子”
     * @param node
     * @return
     */
    private Node removeMin(Node node) {
        if (node == null) {
            // 或者通过size判断是否为空也可以
            throw new IllegalArgumentException("BST is Empty!");
        }
        Node sNode = null;
        while (node.left != null) {
            sNode = node;
            node = node.left;
        }
        Node nod = node;
        node = null;
        if (nod.right != null) {
            sNode.left = nod.right;
        } else {
            sNode.left = null;
        }
        size--;
        return nod;
    }

    /**
     * 删除“树”上最大的元素(在右下角,二分搜索树的性质决定的)
     * 
     * @return 返回该节点的值
     */
    public E removeMax() {
        Node node = removeMax(root);
        return node.data;
    }

    /**
     * 当找到右下角节点时,需判断该节点是否有“左孩子”
     * @param node
     * @return
     */
    private Node removeMax(Node node) {
        if (node == null) {
            throw new IllegalArgumentException("BST is Empty!");
        }
        Node sNode = null;
        while (node.right != null) {
            sNode = node;
            node = node.right;
        }
        Node nod = node;
        node = null;
        if (nod.left != null) {
            sNode.right = nod.left;
        } else {
            sNode.right = null;
        }
        size--;
        return nod;
    }

    /**
     * 删除任意位置的值
     * 
     * @param e
     */
    public void remove(E e) {
        root = remove(root, e);
    }

    /**
     * 删除的具体操作
     * 
     * @param node
     *            树结构
     * @param e
     *            将要删除的数据
     * @return 删除指定数据后的树结构
     */
    private Node remove(Node node, E e) {
        if (e == null || node == null) {
            return null;
        }
        if (e.equals(node.data)) {
            if (node.left != null && node.right != null) {
                Node nod = node;
                node = removeMin(node.right);
                size++;
                node.left = nod.left;
                node.right = nod.right;
                nod.left = nod.right = null;
            } else {
                if (node.left == null && node.right != null) {
                    size--;
                    return node.right;
                } else if (node.right == null && node.left != null) {
                    size--;
                    return node.left;
                } else {
                    size--;
                    return null;
                }
            }
            size--;
            return node;
        } else if (e.compareTo(node.data) < 0) {
            node.left = remove(node.left, e);
        } else if (e.compareTo(node.data) > 0) {
            node.right = remove(node.right, e);
        }
        return node;
    }

    /**
     * 查,前序遍历(递归、非递归)中序遍历(递归、非递归)后序遍历(递归、非递归)层序遍历
     */
    /**
     * 前序遍历
     */
    public void preOrder() {
        preOrder(root);
    }

    /**
     * 前序遍历(递归操作)
     * 
     * @param root
     */
    private void preOrder(Node node) {
        if (node == null) {
            return;
        }
        System.out.print(node.data + " ");
        preOrder(node.left);
        preOrder(node.right);

    }

    /**
     * 前序遍历(非递归操作)
     * 
     * @param root
     */
    @SuppressWarnings("unused")
    private void preOrderOne(Node node) {
        Stack<Node> stack = new Stack<Node>();
        stack.push(node);
        while (!stack.isEmpty()) {
            Node sNode = stack.pop();
            System.out.print(sNode.data + " ");
            if (sNode.right != null) {
                stack.push(sNode.right);
            }
            if (sNode.left != null) {
                stack.push(sNode.left);
            }
        }
    }

    /**
     * 中序遍历
     */
    public void inOrder() {
        inOrderOne(root);
    }

    /**
     * 中序遍历(递归操作)
     * 
     * @param root
     */
    @SuppressWarnings("unused")
    private void inOrder(Node node) {
        if (node == null) {
            return;
        }
        inOrder(node.left);
        System.out.print(node.data + " ");
        inOrder(node.right);
    }

    /**
     * 中序遍历(非递归操作)
     * 
     * @param root
     */
    private void inOrderOne(Node node) {
        Stack<Node> stack = new Stack<Node>();
        Node nod = node;
        while (!stack.isEmpty() || nod != null) {
            while (nod != null) {
                stack.push(nod);
                nod = nod.left;
            }
            Node sNode = stack.pop();
            System.out.print(sNode.data + " ");
            nod = sNode.right;
        }
    }

    /**
     * 后序遍历
     */
    public void postOrder() {
        postOrderOne(root);
    }

    /**
     * 后序遍历(递归操作)
     * 
     * @param node
     */
    @SuppressWarnings("unused")
    private void postOrder(Node node) {
        if (node == null) {
            return;
        }
        postOrder(node.left);
        postOrder(node.right);
        System.out.print(node.data + " ");
    }

    /**
     * 后序遍历(非递归操作)
     * 
     * @param node
     */
    private void postOrderOne(Node node) {
        Stack<Node> stack = new Stack<Node>();
        Node nod = node;
        Node pre = null;
        while (!stack.isEmpty() || nod != null) {
            while (nod != null) {
                stack.push(nod);
                nod = nod.left;
            }
            Node sNode = stack.peek();
            if (sNode.right == null || pre == sNode.right) {
                stack.pop();
                pre = sNode;
                System.out.print(sNode.data + " ");
            } else {
                nod = sNode.right;
            }
        }
    }

    /**
     * 层序遍历
     */
    public void levelTraversal() {
        levelTraversal(root);
    }

    /**
     * 层序遍历(非递归操作)
     * 
     * @param node
     */
    private void levelTraversal(Node node) {
        Queue<Node> queue = new ArrayBlockingQueue<Node>(size);
        if (node != null) {
            queue.offer(node);
        }
        while (!queue.isEmpty()) {
            // System.out.println("取出前:"+queue.size());
            node = queue.poll();
            // System.out.println("取出后:"+queue.size());
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
            System.out.print(node.data + " ");
        }
    }

    /**
     * 获取二分搜索树中数据的个数
     * 
     * @return
     */
    public int getSize() {
        return this.size;
    }

    /**
     * 判空操作
     * 
     * @return true表示为空,false表示不为空
     */
    public boolean isEmpty() {
        return this.size == 0;
    }

    /**
     * 判断数据是否在树中存在
     * 
     * @param e
     * @return true表示存在,false表示不存在
     */
    public boolean contains(E e) {
        return contains(root, e);
    }

    private boolean contains(Node root, E e) {
        if (root != null) {
            if (e.compareTo(root.data) == 0) {
                return true;
            } else if (e.compareTo(root.data) < 0) {
                return contains(root.left, e);
            } else if (e.compareTo(root.data) > 0) {
                return contains(root.right, e);
            }
        }
        return false;
    }

    class Node {
        E data;
        Node left;
        Node right;

        public Node() {
            this(null, null, null);
        }

        public Node(E e) {
            this(e, null, null);
        }

        private Node(E e, Node left, Node right) {
            this.data = e;
            this.left = left;
            this.right = right;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容