树·二叉查找树ADT(二叉搜索树/排序树)

1、定义

  对于每个节点X,它的左子树中所有的项的值小于X的值,右子树所有项的值大于X的值。

  

  如图:任意一个节点,都满足定义,其左子树的所有值小于它,右子树的所有值大于它。

2、平均深度

  在大O模型中,二叉查找树的平均深度是O(logN) 。

  证明:查找某个节点x的算法深度,即从根出发找到节点x的路径长。所有查找的平均深度,就是平均内部路径长。

  1. 假设二叉查找树共N个节点,假设左子树有i个节点,则右子树节点数目:N-i-1。
  2. 假设D(N)表示具有N个基点的内部路径长。则N个节点的树的内部路径长:D(N) = D(i) + D(N-i-1) + N -1。(因为i为左子树,N-i-1 为右子树,所以其实际深度应该加上根节点的深度,所有每个节点都应该+1,除根外共有N-1个节点,所以最后要加上N-1)
  3. j根i在求和中没有实际的区别,都是计数而已。

  对D(N)进行i=(0,N-1)求和: (公式只能用word写出然后截图过来)

                                                            

  求解公式:得到  

                       

3、代码实现(递归)

  二叉查找树完全代码:

  3.1 )根据查找树的性质,我们存放的值必定是可以比较的,所以我们选择 Comparable 作为eo对象的比较。

  3.2)contains方法:是否含有x

    如果存在节点的值为X,则返回true,否则返回false。

  3.3)findMin和findMax方法:

    二叉查找树的所有节点都有其顺序,这两个方法可以方便的找出最大最小值。

  3.4)insert方法:插入x

    插入操作:按照顺序查找,如果找到x,则直接返回树,否则在合适的地方插入x。

  3.5)remove方法:移除x

    删除操作:如果x是叶子节点,则直接删除,返回树,如果x含有左子树或者右子树,或者含有左右子树,则要做适当的调整树结构。

package chapterFour;

import java.nio.BufferUnderflowException;

/**
 * 二叉查找树:
 * 左子树的所有项的值均小于根节点,右子树的所有项的值均大于根节点。
 */
public class BinarySearchTree<T extends Comparable<? super T>> {

    /**
     * 节点类
     *
     * @param <T>
     */
    private static class BinaryNode<T> {

        private T element;
        private BinaryNode<T> left;
        private BinaryNode<T> right;

        BinaryNode(T t) {
            this(t, null, null);
        }

        public BinaryNode(T t, BinaryNode<T> lt, BinaryNode<T> rt) {
            element = t;
            left = lt;
            right = rt;
        }
    }

    // 根节点
    private BinaryNode<T> root;

    /**
     * 构造函数
     */
    public BinarySearchTree() {
        root = null;
    }

    /**
     * 清空整颗树
     */
    public void makeEmpty() {
        root = null;
    }

    /**
     * 判断树是否为空:只需要判断根节点是否为空即可。
     *
     * @return
     */
    public Boolean isEmpty() {
        return root == null;
    }

    /**
     * 是否含有节点x,含有则返回true,没有则返回fales
     *
     * @param x
     * @return
     */
    public boolean contains(T x) {
        return contains(x, root);
    }

    /**
     * 寻找最小值
     *
     * @return
     */
    public T findMin() {
        if (isEmpty()) {
            throw new BufferUnderflowException();
        }
        return findMin(root).element;
    }

    /**
     * 寻找最小值
     *
     * @return
     */
    public T findMax() {
        if (isEmpty()) {
            throw new BufferUnderflowException();
        }
        return findMax(root).element;
    }

    /**
     * 插入
     *
     * @param t
     */
    public void insert(T t) {
        root = insert(t, root);
    }

    /**
     * 删除
     *
     * @param t
     */
    public void remove(T t) {
        root = remove(t, root);
    }

    /**
     * 打印全部
     */
    public void printTree() {
        if (isEmpty()) {
            System.out.println("Empty tree");
        } else {
            printTree(root);
        }
    }

    /**
     * 删除方法:
     * 删除一个节点,如果是叶子节点,那么直接删除就好了,但是如果是某个父节点,那么需要重组部分树节点。
     *
     * @param t
     * @param root
     * @return
     */
    private BinaryNode<T> remove(T t, BinaryNode<T> root) {

        if (root == null) {
            return root;
        }

        int compareResult = t.compareTo(root.element);

        if (compareResult < 0) {
            root.left = remove(t, root.left);
        } else if (compareResult > 0) {
            root.right = remove(t, root.right);
        } else if (root.left != null && root.right != null) {
            root.element = findMin(root.right).element;
            root.right = remove(root.element, root.right);
        } else {

            root = (root.left != null) ? root.left : root.right;
        }
        return root;

    }

    /**
     * 查找树的插入,其实很简单,就一直的递归,然后插入就好了。
     *
     * @param t
     * @param root
     * @return
     */
    private BinaryNode<T> insert(T t, BinaryNode<T> root) {

        // 如果树不存在就创建一棵树
        if (root == null) {
            return new BinaryNode<>(t, null, null);
        }
        int compareResult = t.compareTo(root.element);

        // 如果比root小,就插入到root的左边
        if (compareResult < 0) {
            root.left = insert(t, root.left);
        }
        // 如果比root大,就插入到root的右边
        if (compareResult > 0) {
            root.right = insert(t, root.right);
        }
        // 最后返回树
        return root;

    }

    /**
     * 寻找最大值(方法一,用循环代替递归)
     * 我们不使用递归,加判断的递归,可以用while循环
     *
     * @param root
     * @return
     */
    private BinaryNode<T> findMax(BinaryNode<T> root) {

        if (root == null) {
            return null;
        }

        while (root.right != null) {
            root = root.right;
        }
        return root;
    }

    /**
     * 寻找最小值(方法二,直接使用递归)
     * 我们用递归的方法,遍历所有的左子树,直到最后。
     *
     * @param root
     * @return
     */
    private BinaryNode<T> findMin(BinaryNode<T> root) {
        if (root == null) {
            return null;
        }
        if (root.left == null) {
            return root;
        } else {
            return findMin(root.left);
        }
    }

    /**
     * 如果T是空集,那么可以就返回false。否则,存在T处的项是X,那么就可以返回ture,否则对树对左子树或右子树进行一次递归。
     *
     * @param x
     * @param root
     * @return
     */
    private boolean contains(T x, BinaryNode<T> root) {

        if (root == null) {
            return false;
        }

        // 判断x是在左子树还是右子树
        int compareResult = x.compareTo(root.element);

        if (compareResult < 0) {
            return contains(x, root.left);
        } else {
            return contains(x, root.right);
        }
    }

    /**
     * 按照顺序打印二叉树:中序遍历
     *
     * @param tb
     */
    private void printTree(BinaryNode<T> tb) {
        if (tb != null) {
            printTree(tb.left);
            System.out.println(tb.element);
            printTree(tb.right);
        }
    }

}

原文地址:https://www.cnblogs.com/dhcao/p/10428502.html

时间: 2024-10-11 14:51:24

树·二叉查找树ADT(二叉搜索树/排序树)的相关文章

判断一棵树是否为二叉搜索树(二叉排序树) python

输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的节点 #方法1,直接判断 直接判断的关键在于不能只是单纯地判断根.左.右三个节点的大小关系,左子树的右节点不仅要大于父节点,还要小于父节点的父节点,右子树的左节点

数据结构学习笔记04树(二叉树、二叉搜索树、平衡二叉树)

一.树 树的基本术语 ①结点的度(Degree):结点的子树个数 ②树的度:树的所有结点中最大的度数 ③叶结点(Leaf):度为0的结点 ④父结点(Parent):有子树的结点是其子树的根结点的父结点 ⑤子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点:子结点也称孩子结点. ⑥兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点. ⑦路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结点.路径所包含边

数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中: 如果BST树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树 的搜索性能逼近二分查找:但它比连续内存空间的二分查找的优点是,改变BST树结构 插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销: 如:

判断一棵树是否是二叉搜索树

前两天写过一篇博文<二叉搜索树基本操作实现>,为了更深入了解二叉搜索树的性质,本文实现判断一棵树是否为二叉搜索树算法. 二叉搜索树的性质: 任意节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树中的每一个节点的键值. 构造二叉树的节点定义为: struct TreeNode{ int data; TreeNode *left; TreeNode *right; }; 方法1 (错误) 对每一个节点,检测其值是否大于左子树节点,是否小于右子树节点.思路很简单,代码实现如下: bool

平衡二叉搜索树(AVL树,红黑树)数据结构和区别

平衡二叉搜索树(Balanced Binary Search Tree) 经典常见的自平衡的二叉搜索树(Self-balancing Binary Search Tree)有 ① AVL树 :Windows NT 内核中广泛使用 ② 红黑树:C++ STL(比如 map.set )Java 的 TreeMap.TreeSet.HashMap.HashSet  Linux 的进程调度  Ngix 的 timer 管理 1 AVL树  vs  红黑树 ①AVL树 平衡标准比较严格:每个左右子树的高度

简单实现二叉搜索树 (查找树)

直接看代码 /** * @author <a href=mailto:[email protected]>maple</a> * @since 2018-11-25 11:40 PM */ // 二分搜索树 // 由于Key需要能够进行比较,所以需要extends Comparable<Key> public class BST<Key extends Comparable<Key>, Value> { // 树中的节点为私有的类, 外界不需要了

【剑指offer】【树】54.二叉搜索树的第k大节点

二叉搜索树的第k大节点 递归法 中序遍历的二叉搜索树序列为单调递增的序列,将中序遍历的结果放到vector中,第k大的数为v.size()-k位置的数 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ cl

数据结构|-二叉查找树(二叉搜索树)的链式存储结构的实现

二叉排序树,又称为二叉查找树. 它或者是一棵空树,或者是具有下列性质的二叉树. 若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值: 若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值: 它的左右子树也分别为二叉排序树. 优点: 1,排序方便 2,方便查找 3,方便插入和删除 二叉排序树的插入数据: 因为二叉排序树中所有的数都符合排序树的特点,所以任意插入一个数时,都能在遍历树的过程中找到其应该放置的正确位置 二叉排序树的删除数据: 三种情况: 1,叶子结点:直接删除该叶子

查找树ADT——二叉搜索树

在以下讨论中,虽然任意复杂的关键字都是允许的,但为了简单起见,假设它们都是整数,并且所有的关键字是互异的. 总概   使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有的关键字值大于X的关键字值.注意,这意味着该树所有的元素可以用某种统一的方式排序. 操作 #ifndef __Tree_H struct TreeNode *Position; typedef struct TreeNode *SearchTree; SearchTr