二叉查找树即搜索二叉树,或者二叉排序树(BSTree),学习回顾一下有关的知识。

>>关于二叉查找树

二叉查找树(Binary Search Tree)是指一棵空树或者具有下列性质的二叉树:
1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3. 任意节点的左、右子树也分别为二叉查找树。
4. 没有键值相等的节点,这个特征很重要,可以帮助理解二叉排序树的很多操作。
二叉查找树具有很高的灵活性,对其优化可以生成平衡二叉树,红黑树等高效的查找和插入数据结构。

>>基本性质

(1)二叉查找树是一个递归的数据结构,对二叉查找树进行中序遍历,可以得到一个递增的有序序列。
(2)二叉查找树上基本操作的执行时间和树的高度成正比。

对一棵n个节点的完全二叉树来说,树的高度为lgn,这些操作的最坏情况运行时间为O(lg n),而如果是线性链表结构,这些操作的最坏运行时间是O(n)。
一棵随机构造的二叉查找树的期望高度为O(lg n),但实际中并不能总是保证二叉查找树是随机构造的,
有些二叉查找树的变形能保证各种基本操作的最坏情况性能,比如红黑树的高度为O(lg n),而B树对维护随机访问的二级存储器上的数据库特别有效。

注意对复杂度的理解,所谓的O(lg n)就是指复杂度是对数级别,是数量级的比较,和对数的底数其实没关系,

只要底数是大于1的,就是相同的数量级,有些书上说二叉查找树的复杂度是O(log2-n),指的是相同的时间复杂度。

>>前驱和后继节点

一个节点的后继是该节点的后一个,即比该节点键值稍大的节点。
给定一个二叉查找树中的节点,找出在中序遍历顺序下某个节点的前驱和后继。
如果树中所有关键字都不相同,则某一节点x的前驱就是小于key[x]的所有关键字中最大的那个节点,后继即是大于key[x]中的所有关键字中最小的那个节点。根据二叉查找树的结构和性质,不用对关键字做任何比较,就可以找到某个节点的前驱和后继。

>>查找、插入与删除

(1)查找
利用二叉查找树左小右大的性质,可以很容易实现查找任意值和最大/小值。

在二叉查找树中查找一个给定的关键字k的过程与二分查找很类似

首先是关键字k与树根的关键字进行比较,如果k比根的关键字大,则在根的右子树中查找,否则在根的左子树中查找,重复此过程,直到找到与遇到空节点为止。

在二叉查找树中查找x的过程如下:
1.若二叉树是空树,则查找失败。
2.若x等于根节点的数据,则查找成功,否则。
3.若x小于根节点的数据,则递归查找其左子树,否则。
4.递归查找其右子树。

(2)插入
二叉树查找树b插入操作x的过程如下:
1.若b是空树,则直接将插入的节点作为根节点插入。
2.x等于b的根节点的数据的值,则直接返回,否则。
3.若x小于b的根节点的数据的值,则将x要插入的节点的位置改变为b的左子树,否则。
4.将x要出入的节点的位置改变为b的右子树。

(3)删除


假设从二叉查找树中删除给定的结点z,分三种情况讨论:
1.节点z为叶子节点,没有孩子节点,那么直接删除z,修改父节点的指针即可。
2.节点z只有一个子节点或者子树,将节点z删除,根据二叉查找树的性质,将z的父节点与子节点关联就可以了。
3.节点Z有两个子节点,删除Z该怎样将Z的父结点与这两个孩子结点关联呢?
在删去节点Z之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整。
这种情况下可以用Z的后继节点来替代Z。
实现方法就是将后继从二叉树中删除,将后继的数据覆盖到Z中。

>>代码实现

主要参考《数据结构与算法分析—Java语言实现》:

public class BinarySearchTree <T extends Comparable<? super T>>{

	//节点数据结构 静态内部类
	static class BinaryNode<T>{
		T data;
		BinaryNode<T> left;
		BinaryNode<T> right;
		public BinaryNode(){
			data=null;
		}
		public BinaryNode(T data) {
			this(data,null,null);
		}
		public BinaryNode(T data,BinaryNode<T> left,BinaryNode<T> right){
			this.data=data;
			this.left=left;
			this.right=right;
		}
	}

	//私有的头结点
	private BinaryNode<T> root;

	//构造一棵空二叉树
	public BinarySearchTree(){
		root=null;
	}
	//二叉树判空
	public boolean isEmpty(){
		return root==null;
	}
	//清空二叉树
	public void clear(){
		root=null;
	}

	//检查某个元素是否存在
	public boolean contains(T t){
		return contains(t,root);
	}

	/**
	 * 从某个节点开始查找某个元素是否存在
	 * 在二叉查找树中查找x的过程如下:
	 * 1、若二叉树是空树,则查找失败。
	 * 2、若x等于根结点的数据,则查找成功,否则。
	 * 3、若x小于根结点的数据,则递归查找其左子树,否则。
	 * 4、递归查找其右子树。
	 */
	public boolean contains(T t,BinaryNode<T> node){
		if(node==null){
			return false;
		}
		/**
		 * 这就是为什么使用Comparable的泛型
		 * compareTo的对象也必须是实现了Comparable接口的泛型,
		 * 所以参数必须是BinaryNode<T> node格式
		 */
		int result=t.compareTo(node.data);
		if(result>0){//去右子树查找
			return contains(t,node.right);
		}else if(result<0){//去左子树查找
			return contains(t,node.left);
		}else{
			return false;
		}
	}

	//插入元素
	public void insert(T t){
		root=insert(t,root);
	}

	/**
	 * 将节点插入到以某个节点为头的二叉树中
	 * 这个插入其实也是一个递归的过程
	 * 递归最深层的返回结果一个包含要插入的节点子树的头节点
	 */
	public BinaryNode insert(T t,BinaryNode<T> node){
		//如果是空树,直接构造一棵新的二叉树
		if(node==null){
			return new BinaryNode<T>(t);
		}

		int result=t.compareTo(node.data);

		if(result<0){
			node.left=insert(t,node.left);
		}else if(result>0){
			node.right=insert(t,node.right);
		}else{
			;//即要插入的元素和头节点值相等,直接返回即可
		}
		return node;
	}

	/**
	 * 删除元素
	 * 返回调整后的二叉树头结点
	 */
	public BinaryNode delete(T t){
		return delete(t,root);

	}

	/**
	 * 在以某个节点为头结点的树结构中删除元素
	 * 首先需要找到该关键字所在的节点p,然后具体的删除过程可以分为几种情况:
	 * p没有子女,直接删除p
	 * p有一个子女,直接删除p
	 * p有两个子女,删除p的后继q(q至多只有一个子女)
	 * 确定了要删除的节点q之后,就要修正q的父亲和子女的链接关系,
	 * 然后把q的值替换掉原先p的值,最后把q删除掉
	 */
	public BinaryNode delete(T t,BinaryNode<T> node){
		if(node==null){//节点为空还要啥自行车
			return node;
		}
		/**
		 * 首先要找到这个节点,所以还是得比较
		 */
		int result=t.compareTo(node.data);

		/**
		 * 去左半部分找这个节点,
		 * 找到节点result==0,这个递归就停止
		 */
		if(result<0){
			node.left=delete(t,node.left);
		}else if(result>0){//去右半部分找这个节点
			node.right=delete(t,node.right);
		}
		/**
		 * 如果这个节点的左右孩子都不为空,那么找到当前节点的后继节点,
		 *
		 */
		if(node.left!=null && node.right!=null){
			/**
			 * node节点的右子树部分的最小节点,实际上就是它的后继节点
			 * 得到后继节点的值
			 */
			node.data = findMin(node.right).data;
			/**
			 * 这个过程并不是删除后继节点,是一步一步的把所有的节点都替换上来
			 */
	        node.right = delete(node.data,node.right);
		}else{
			/**
			 * 如果二叉搜索树中一个节点是完全节点,
			 * 那么它的前驱和后继节点一定在以它为头结点的子树中,应该是这样的
			 * 来到了只有一个头节点和一个子节点的情况
			 */
			node = (node.left!=null)?node.left:node.right;
		}
		//此处的node,是经过调整后的传入的root节点
		return node;

	}

	/**
	 * 返回二叉树中的最小值节点
	 * 此时无比想念大根堆和小根堆
	 */
	public BinaryNode<T> findMin(BinaryNode node){
		if(node==null)
			return null;
		/**
		 * 如果node不为空,就递归的去左边找
		 * 最小值节点肯定是左孩子为空的节点
		 */
		if(node.left!=null)
			node=findMin(node.left);
		return node;
	}

}

  

参考《算法导论》、

《数据结构与算法分析—Java语言实现》 

二叉查找树维基百科

二叉树学习笔记之二叉查找树(BSTree)的更多相关文章

  1. 二叉树学习笔记之B树、B+树、B*树

    动态查找树主要有二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree), 红黑树 (Red-Black Tree ), 都是典型的 ...

  2. 二叉树学习笔记之经典平衡二叉树(AVL树)

    二叉查找树(BSTree)中进行查找.插入和删除操作的时间复杂度都是O(h),其中h为树的高度.BST的高度直接影响到操作实现的性能,最坏情况下,二叉查找树会退化成一个单链表,比如插入的节点序列本身就 ...

  3. BST,Splay平衡树学习笔记

    BST,Splay平衡树学习笔记 1.二叉查找树BST BST是一种二叉树形结构,其特点就在于:每一个非叶子结点的值都大于他的左子树中的任意一个值,并都小于他的右子树中的任意一个值. 2.BST的用处 ...

  4. 《数据结构与算法分析》学习笔记(五)——二叉树

    (一)查找二叉树ADT 1.二叉查找树ADT性质:     对于树中的每个节点X,它的左子树中所有关键字值都小于X的关键字值,而它的右子树值的关键字值都大于X的关键字值. 2.一些ADT的基本操作 结 ...

  5. [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家

    1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...

  6. javaSE学习笔记(10)---List、Set

    javaSE学习笔记(10)---List.Set 1.数据存储的数据结构 常见的数据结构 数据存储的常用结构有:栈.队列.数组.链表和红黑树. 1.栈 栈:stack,又称堆栈,它是运算受限的线性表 ...

  7. 「学习笔记」Treap

    「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...

  8. 从实例学习 Go 语言、"并发内容" 学习笔记及心得体会、Go指南

    第一轮学习 golang "并发内容" 学习笔记,Go指南练习题目解析.使用学习资料 <Go-zh/tour tour>.记录我认为会比较容易忘记的知识点,进行补充,整 ...

  9. java学习笔记13--比较器(Comparable、Comparator)

    java学习笔记13--比较器(Comparable.Comparator) 分类: JAVA 2013-05-20 23:20 3296人阅读 评论(0) 收藏 举报 Comparable接口的作用 ...

随机推荐

  1. Facebook内部高效工作PPT指南

    Facebook内部高效工作PPT指南 Facebook 内部分享:不论你如何富有,你都赚不到更多的时间,你也回不到过去.没有那么多的假如,只有指针滴答的时光飞逝和你应该好好把握的现在,以下25张PP ...

  2. Python 科学计算涉及模块

    模块1.数据基础 numpy 模块2.数值运算 scipy 模块3.符号运算 sympy 模块4.图形绘制 matplotlib

  3. IOS学习笔记—苹果推送机制APNs

    转自:唐韧_Ryan http://blog.csdn.net/ryantang03/article/details/8482259 推送是解决轮询所造成的流量消耗和 电量消耗的一个比较好的解决方案, ...

  4. Metasploit自动攻击和选择模块攻击详解

    Author:魔术@Freebuf.com 0×1自动攻击 终端启动Metasploit,因为我现在Source Code,所以这样启动! 连接数据库 安装方法,执行以下命令即可(请用ROOT执行). ...

  5. 通过开源程序同时解决DNS劫持和DNS污染的问题

    我们知道,某些网络运营商为了某些目的,对DNS进行了某些操作,导致使用ISP的正常上网设置无法通过域名取得正确的IP地址.常用的手段有:DNS劫持和DNS污染.关于DNS劫持和DNS污染的区别,请查找 ...

  6. RTSP RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议

    RTSP 编辑 RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学.网景和RealNetwo ...

  7. GTP V0 和 GTP V1

    GTP概述 GTP(GPRS Tunnelling Protocol)协议应用在SGSN 和GGSN 之间,为各个移动台(MS) 建立GTP 通道,GTP 通道是 GPRS服务节点(GSN) 之间的安 ...

  8. Base64封装类

    using System;using System.Collections.Generic;using System.Linq;using System.Web; /// <summary> ...

  9. C# JavascriptSerializer与匿名对象打造Json的完美工具

    一:背景 在web项目中经常需要生成json数据,返回给前端ajax. 无论是ashx,还是WebMethod,可以人工的用字符串去拼接,最终得到json数据. 有没有更好的方法呢?我个人推荐使用Ja ...

  10. WP8版微信5.4发布 新增夜间模式 暂没小视频

    经过近一个月的内测,WP8版的微信终于更新了v 5.4版本.新增聊天中的照片墙.识别图片二维码.夜间模式等功能,还对资源占用情况进行了优化,让程序可以更流畅的在低配置设备上运行. 不过,WP8版微信5 ...