前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java数据结构与算法解析(五)——二叉查找树

Java数据结构与算法解析(五)——二叉查找树

作者头像
老马的编程之旅
发布2022-06-22 12:43:27
2740
发布2022-06-22 12:43:27
举报
文章被收录于专栏:深入理解Android

二叉查找树简介

二叉查找树(Binary Search Tree),又被称为二叉搜索树。 它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。那么,这棵树就是二叉查找树。如下图所示:

这里写图片描述
这里写图片描述

在二叉查找树中: (1) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; (2) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; (3) 任意节点的左、右子树也分别为二叉查找树。 (4) 没有键值相等的节点(no duplicate nodes)。

二叉查找树的实现

1.二叉查找树节点实现

代码语言:javascript
复制
public class BinaryNode<T> {
    private T element;
    private BinaryNode<T> left;
    private BinaryNode<T> right;

    public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
        this.element = element;
        this.left = left;
        this.right = right;
    }

    public BinaryNode(T element) {
        this(element, null, null);
    }

}

(1) element–当前节点的值 (2) right – 它指向当前节点的右孩子。 (3) parent – 它指向当前节点的父结点。

2.contains方法的实现

如果在树T中存在含有项X的节点,那么contains方法返回true,否则返回false.如果树T是空集,则返回false.

代码语言:javascript
复制
public boolean contains(T t, BinaryNode<T> node) {
        if (t == null) {
            return false;
        }

        int campareResult = t.compareTo(node.element);
        if (campareResult < 0) {
            return contains(t, node.left);
        } else if (campareResult > 0) {
            return contains(t, node.right);
        } else {
            return true;
        }
    }

从根节点开始查找该值,如果根节点匹配,则直接返回true,否则和根节点的值进行比较,然后递归遍历左子树或右子树进行查找。

3.findMin方法和findMax方法

代码语言:javascript
复制
 public T findMax() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException();
        }
        return findMax(mRoot).element;
    }

    private BinaryNode<T> findMax(BinaryNode<T> node) {
        if (node != null) {
            while (node.right != null) {
                node = node.right;
            }
        }
        return node;
    }

对于findMax方法,如果存在右子树,则递归遍历,终止点就是最大的元素。否则,根节点就是最大的元素。

代码语言:javascript
复制
 public T findMin(){
        if (isEmpty()) {
            throw new IndexOutOfBoundsException();
        }
        return findMin(mRoot).element;
    }

    private BinaryNode<T> findMin(BinaryNode<T> node) {
        if (node != null) {
            while (node.left != null) {
                node = node.left;
            }
        }
        return node;
    }

对于findMin方法,如果存在左子树,则递归遍历,终止点就是最小的元素。否则,根节点就是最小的元素。

4.insert方法 将一个新的元素X插入到树T中,可以先通过contains方法去查找该元素是否存在,如果存在,则什么都不做,否则将X插入到遍历路径上的最后一点。

代码语言:javascript
复制
public void insert(T t) {
        mRoot = insert(t, mRoot);
    }

    public BinaryNode<T> insert(T t, BinaryNode<T> node) {
        if (node == null) {

            return new BinaryNode<T>(t, null, null);
        }

        int compareResult = t.compareTo(node.element);
        if (compareResult > 0) {
            node.right = insert(t, node.right);
        } else if (compareResult < 0) {
            node.left = insert(t, node.left);
        }

        return node;
    }

5.remove方法

代码语言:javascript
复制
public void remove(T t) {
        mRoot = remove(t, mRoot);
    }

    public BinaryNode<T> remove(T t, BinaryNode<T> node) {
        if (node == null) {
            return node;
        }
        int compareResult = t.compareTo(node.element);
        if (compareResult > 0) {
            node.right = remove(t, node.right);
        } else if (compareResult < 0) {
            node.left = remove(t, node.left);
        } else if (node.left != null && node.right != null) {
            node.element = findMin(node.right).element;
            node.right = remove(node.element, node.right);
        } else {
            node = (node.left != null) ? node.left : node.right;
        }
        return node;

    }

对于删除,最复杂的是该将被删除的节点A具有两个儿子的情况,一般是该节点的右子树最小的节点B代替节点A,然后在B原来的位置删除掉节点B。

上面的代码能够完成删除工作,但效率并不高,因为它沿着树进行两趟搜索来查找和删除右子树中最小的节点。

如果删除的次数不多,通常使用懒惰删除:当一个元素要被删除时,它仍在树中,而只是标记为删除。

特别是删除算法会使得左子树比右子树深,因为我们总是用右子树的一个来代替删除的节点。会造成二叉查找树,严重的不平衡。

5.二叉查找树完整代码

代码语言:javascript
复制
public class BinarySearchTree<T extends Comparable<?
        super T>> {

    private BinaryNode<T> mRoot;

    public void makeEmpty() {
        mRoot = null;
    }

    public boolean isEmpty() {
        return mRoot == null;
    }

    public boolean contains(T t) {
        return contains(t, mRoot);
    }

    public boolean contains(T t, BinaryNode<T> node) {
        if (t == null) {
            return false;
        }

        int campareResult = t.compareTo(node.element);
        if (campareResult < 0) {
            return contains(t, node.left);
        } else if (campareResult > 0) {
            return contains(t, node.right);
        } else {
            return true;
        }
    }

    public T findMax() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException();
        }
        return findMax(mRoot).element;
    }

    private BinaryNode<T> findMax(BinaryNode<T> node) {
        if (node != null) {
            while (node.right != null) {
                node = node.right;
            }
        }
        return node;
    }

    public T findMin() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException();
        }
        return findMin(mRoot).element;
    }

    private BinaryNode<T> findMin(BinaryNode<T> node) {
        if (node != null) {
            while (node.left != null) {
                node = node.left;
            }
        }
        return node;
    }

    public void insert(T t) {
        mRoot = insert(t, mRoot);
    }

    public BinaryNode<T> insert(T t, BinaryNode<T> node) {
        if (node == null) {

            return new BinaryNode<T>(t, null, null);
        }

        int compareResult = t.compareTo(node.element);
        if (compareResult > 0) {
            node.right = insert(t, node.right);
        } else if (compareResult < 0) {
            node.left = insert(t, node.left);
        }

        return node;
    }

    public void remove(T t) {
        mRoot = remove(t, mRoot);
    }

    public BinaryNode<T> remove(T t, BinaryNode<T> node) {
        if (node == null) {
            return node;
        }
        int compareResult = t.compareTo(node.element);
        if (compareResult > 0) {
            node.right = remove(t, node.right);
        } else if (compareResult < 0) {
            node.left = remove(t, node.left);
        } else if (node.left != null && node.right != null) {
            node.element = findMin(node.right).element;
            node.right = remove(node.element, node.right);
        } else {
            node = (node.left != null) ? node.left : node.right;
        }
        return node;

    }

    private static class BinaryNode<T> {
        private T element;
        private BinaryNode<T> left;// 左孩子
        private BinaryNode<T> right;// 右孩子

        public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
            this.element = element;
            this.left = left;
            this.right = right;
        }

        public BinaryNode(T element) {
            this(element, null, null);
        }

    }
}

二叉树的遍历

1.前序遍历 若二叉树非空,则执行以下操作: (1) 访问根结点; (2) 先序遍历左子树; (3) 先序遍历右子树。

这里写图片描述
这里写图片描述

前序遍历代码

代码语言:javascript
复制
 //前序遍历
    private void preOrder(BinaryNode<T> tree) {
        if(tree != null) {
            System.out.print(tree.element+" ");
            preOrder(tree.left);
            preOrder(tree.right);
        }
    }

    public void preOrder() {
        preOrder(mRoot);
    }

2.中序遍历 若二叉树非空,则执行以下操作: (1) 中序遍历左子树; (2) 访问根结点; (3) 中序遍历右子树。

这里写图片描述
这里写图片描述

中序遍历代码

代码语言:javascript
复制
private void inOrder(BinaryNode<T> tree) {
        if(tree != null) {
            inOrder(tree.left);
            System.out.print(tree.element+" ");
            inOrder(tree.right);
        }
    }

    public void inOrder() {
        inOrder(mRoot);
    }

3.后序遍历 若二叉树非空,则执行以下操作: (1) 后序遍历左子树; (2) 后序遍历右子树; (3) 访问根结点。

这里写图片描述
这里写图片描述

后序遍历代码

代码语言:javascript
复制
 private void postOrder(BinaryNode<T> tree) {
        if(tree != null)
        {
            postOrder(tree.left);
            postOrder(tree.right);
            System.out.print(tree.element+" ");
        }
    }

    public void postOrder() {
        postOrder(mRoot);
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二叉查找树简介
  • 二叉查找树的实现
  • 二叉树的遍历
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档