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写出然后截图过来,后续用markdown写好了)

                                                            

  求解公式:得到  

                       

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);
}
} }

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

  1. 树-二叉搜索树-AVL树

    树-二叉搜索树-AVL树 树 树的基本概念 节点的度:节点的儿子数 树的度:Max{节点的度} 节点的高度:节点到各叶节点的最大路径长度 树的高度:根节点的高度 节点的深度(层数):根节点到该节点的路 ...

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

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  3. 数据结构中的树(二叉树、二叉搜索树、AVL树)

    数据结构动图展示网站 树的概念 树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合.它是由n(n>=1)个有限节点组成一个具有 ...

  4. 树(二叉树 & 二叉搜索树 & 哈夫曼树 & 字典树)

    树:n(n>=0)个节点的有限集.有且只有一个root,子树的个数没有限制但互不相交.结点拥有的子树个数就是该结点的度(Degree).度为0的是叶结点,除根结点和叶结点,其他的是内部结点.结点 ...

  5. 高度平衡的二叉搜索树(AVL树)

    AVL树的基本概念 AVL树是一种高度平衡的(height balanced)二叉搜索树:对每一个结点x,x的左子树与右子树的高度差(平衡因子)至多为1. 有人也许要问:为什么要有AVL树呢?它有什么 ...

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

    树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树 ...

  7. HDU 3179 二叉搜索树(树的建立)

    二叉搜索树 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  8. 查找树ADT——二叉搜索树

    在以下讨论中,虽然任意复杂的关键字都是允许的,但为了简单起见,假设它们都是整数,并且所有的关键字是互异的. 总概   使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有关键字值小于 ...

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

    数据结构中常见的树(BST二叉搜索树.AVL平衡二叉树.RBT红黑树.B-树.B+树.B*树) 二叉排序树.平衡树.红黑树 红黑树----第四篇:一步一图一代码,一定要让你真正彻底明白红黑树 --- ...

随机推荐

  1. 一、VS2017 的创建程序

    1.1 创建第一个子程序 1.1.1 创建项目 打开 VS2017,选择菜单栏 [文件]->[新建]->[项目]: 点击[确定]后,弹出如下界面: 点击[下一步]: 选择 空项目, 然后点 ...

  2. 【Django】git建仓上传时遇到的小问题

    根据教程 http://tutorial.djangogirls.org/zh/deploy/,在github上建仓上传项目文件. 执行到 git push -u origin master 时,输入 ...

  3. Cisco Common Service Platform Collector - Hardcoded Credentials(CVE-2019-1723)

    Cisco Common Service Platform Collector - Hardcoded Credentials 思科公共服务平台收集器-硬编码凭证(CVE-2019-1723) htt ...

  4. VM4061 layui.js:2 Layui hint: form is not a valid module

    报错:VM4061 layui.js:2 Layui hint: form is not a valid module 解决办法:当你遇到类似这样报错,说某某某不是一个有效的模块时,不防在layui. ...

  5. c语言 贪食蛇小游戏

    ---恢复内容开始--- #include <stdio.h>#include <windows.h>#include <stdlib.h>#include < ...

  6. CF961G Partitions

    传送门 luogu 显然每个数的贡献可以一起算感性理解一下,于是答案就是权值总和乘以每个数被算了几次 那个"集合大小为\(|S|\)的集合权值为权值和乘\(|S|\)",可以看成一 ...

  7. kvm 搭建

    一,准备环境   物理机 虚拟机 操作系统 CentOS 6.8 x64 CentOS 6.8 x64 CPU/内存 10核超线程x2/64G 2核/4G 外网IP -- 内网IP eth1_192. ...

  8. MacOS安装Go2Shell

    1 去官网下载安装MacOS最新版本 https://zipzapmac.com/Go2Shell 2 下一步下一步安装 3 设置 打开终端设置, open -a Go2Shell --args co ...

  9. 用python在后端将数据写入到数据库并读取

    用python在后端将数据写入到数据库: # coding:utf- import pandas as pd from sqlalchemy import create_engine # 初始化数据库 ...

  10. Python之List列表的循环和切片

    一.循环(for):输出列表中的每一个元素 stus=['杨静','王志华','王银梅','乔美玲'] #一个个输出列表元素 for s in stus: print('s 是 %s'%s) s 是 ...