二叉搜索树算法详解与Java实现
二叉查找树可以递归地定义如下,二叉查找树或者是空二叉树,或者是满足下列性质的二叉树:
(1)若它的左子树不为空,则其左子树上任意结点的关键字的值都小于根结点关键字的值。
(2)若它的右子树不为空,则其右子树上任意结点的关键字的值都大于根节点关键字的值。
(3)它的左、右子树本身又是一个二叉查找树。

从性能上来说如果二叉查找树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么二叉查找树的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变二叉查找树结构(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销。二叉查找树可以表示按顺序序列排列的数据集合,因此二叉查找树也被称为二叉排序树,并且同一个数据集合可以表示为不同的二叉查找树。二叉查找树的结点的数据结构定义为:
struct celltype{
records data;
celltype * lchild, * rchild;
}
typedef celltype * BST;
在Java中,节点的数据结构定义如下:
package wx.algorithm.search.bst;
/**
* Created by apple on 16/7/29.
*/
/**
* @function 二叉搜索树中的节点
*/
public class Node {
//存放节点数据
int data;
//指向左子节点
Node left;
//指向右子节点
Node right;
/**
* @function 默认构造函数
* @param data 节点数据
*/
public Node(int data) {
this.data = data;
left = null;
right = null;
}
}
查找
而二叉查找树的查找过程为从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字。

BST Search(keytype k, BST F){
//在F所指的二叉查找树中查找关键字为k的记录。若成功,则返回响应结点的指针,否则返回空
if(F == NULL) //查找失败
return NULL;
else if(k == F -> data.key){ //查找成功
return F;
}
else if (k < F -> data.key){ //查找左子树
return Search(k,F -> lchild);
}
else if (k > F -> data.key){ //查找右子树
return Search(k,F -> rchild);
}
}
插入
把一个新的记录R插入到二叉查找树,应该保证在插入之后不破坏二叉查找树的结构性质。因此,为了执行插入操作首先应该查找R所在的位置。查找时,仍然采用上述的递归算法。若查找失败,则把包含R的结点插在具有空子树位置,若查找成功,则不执行插入,操作结束。

void Insert(records R, BST &F){
//在F所指的二叉查找树中插入一个新纪录R
if(F == NULL){
F = new celltype;
F -> data = R;
F -> lchild = NULL;
F -> rchild = NULL;
}
else if (R.key < F -> data.key){
Insert(R,F -> lchild);
}else if(R.key > F -> data.key){
Insert(R,F -> rchild);
}
//如果 R.key == F -> data.key 则返回
}
删除
删除叶节点

删除只有一个子节点的内部节点

删除有两个子节点的内部节点
如果我们进行简单的替换,那么可能碰到如下情况:

因此我们要在子树中选择一个合适的替换节点,替换节点一般来说会是右子树中的最小的节点:

Java 实现
BinarySearchTree的Java版本代码参考BinarySearchTree:
package wx.algorithm.search.bst;
/**
* Created by apple on 16/7/29.
*/
/**
* @function 二叉搜索树的示范代码
*/
public class BinarySearchTree {
//指向二叉搜索树的根节点
private Node root;
//默认构造函数
public BinarySearchTree() {
this.root = null;
}
/**
* @param id 待查找的值
* @return
* @function 默认搜索函数
*/
public boolean find(int id) {
//从根节点开始查询
Node current = root;
//当节点不为空
while (current != null) {
//是否已经查询到
if (current.data == id) {
return true;
} else if (current.data > id) {
//查询左子树
current = current.left;
} else {
//查询右子树
current = current.right;
}
}
return false;
}
/**
* @param id
* @function 插入某个节点
*/
public void insert(int id) {
//创建一个新的节点
Node newNode = new Node(id);
//判断根节点是否为空
if (root == null) {
root = newNode;
return;
}
//设置current指针指向当前根节点
Node current = root;
//设置父节点为空
Node parent = null;
//遍历直到找到第一个插入点
while (true) {
//先将父节点设置为当前节点
parent = current;
//如果小于当前节点的值
if (id < current.data) {
//移向左节点
current = current.left;
//如果当前节点不为空,则继续向下一层搜索
if (current == null) {
parent.left = newNode;
return;
}
} else {
//否则移向右节点
current = current.right;
//如果当前节点不为空,则继续向下一层搜索
if (current == null) {
parent.right = newNode;
return;
}
}
}
}
/**
* @param id
* @return
* @function 删除树中的某个元素
*/
public boolean delete(int id) {
Node parent = root;
Node current = root;
//记录被找到的节点是父节点的左子节点还是右子节点
boolean isLeftChild = false;
//循环直到找到目标节点的位置,否则报错
while (current.data != id) {
parent = current;
if (current.data > id) {
isLeftChild = true;
current = current.left;
} else {
isLeftChild = false;
current = current.right;
}
if (current == null) {
return false;
}
}
//如果待删除的节点没有任何子节点
//直接将该节点的原本指向该节点的指针设置为null
if (current.left == null && current.right == null) {
if (current == root) {
root = null;
}
if (isLeftChild == true) {
parent.left = null;
} else {
parent.right = null;
}
}
//如果待删除的节点有一个子节点,且其为左子节点
else if (current.right == null) {
//判断当前节点是否为根节点
if (current == root) {
root = current.left;
} else if (isLeftChild) {
//挂载到父节点的左子树
parent.left = current.left;
} else {
//挂载到父节点的右子树
parent.right = current.left;
}
} else if (current.left == null) {
if (current == root) {
root = current.right;
} else if (isLeftChild) {
parent.left = current.right;
} else {
parent.right = current.right;
}
}
//如果待删除的节点有两个子节点
else if (current.left != null && current.right != null) {
//寻找右子树中的最小值
Node successor = getSuccessor(current);
if (current == root) {
root = successor;
} else if (isLeftChild) {
parent.left = successor;
} else {
parent.right = successor;
}
successor.left = current.left;
}
return true;
}
/**
* @param deleleNode
* @return
* @function 在树种查找最合适的节点
*/
private Node getSuccessor(Node deleleNode) {
Node successsor = null;
Node successsorParent = null;
Node current = deleleNode.right;
while (current != null) {
successsorParent = successsor;
successsor = current;
current = current.left;
}
if (successsor != deleleNode.right) {
successsorParent.left = successsor.right;
successsor.right = deleleNode.right;
}
return successsor;
}
/**
* @function 以中根顺序遍历树
*/
public void display() {
display(root);
}
private void display(Node node) {
//判断当前节点是否为空
if (node != null) {
//首先展示左子树
display(node.left);
//然后展示当前根节点的值
System.out.print(" " + node.data);
//最后展示右子树的值
display(node.right);
}
}
}
测试函数:
package wx.algorithm.search.bst;
import org.junit.Before;
import org.junit.Test;
/**
* Created by apple on 16/7/30.
*/
public class BinarySearchTreeTest {
BinarySearchTree binarySearchTree;
@Before
public void setUp() {
binarySearchTree = new BinarySearchTree();
binarySearchTree.insert(3);
binarySearchTree.insert(8);
binarySearchTree.insert(1);
binarySearchTree.insert(4);
binarySearchTree.insert(6);
binarySearchTree.insert(2);
binarySearchTree.insert(10);
binarySearchTree.insert(9);
binarySearchTree.insert(20);
binarySearchTree.insert(25);
binarySearchTree.insert(15);
binarySearchTree.insert(16);
System.out.println("原始的树 : ");
binarySearchTree.display();
System.out.println("");
}
@Test
public void testFind() {
System.out.println("判断4是否存在树中 : " + binarySearchTree.find(4));
}
@Test
public void testInsert() {
}
@Test
public void testDelete() {
System.out.println("删除值为2的节点 : " + binarySearchTree.delete(2));
binarySearchTree.display();
System.out.println("\n 删除有一个子节点值为4的节点 : " + binarySearchTree.delete(4));
binarySearchTree.display();
System.out.println("\n 删除有两个子节点的值为10的节点 : " + binarySearchTree.delete(10));
binarySearchTree.display();
}
}
二叉搜索树算法详解与Java实现的更多相关文章
- 【转载】图解:二叉搜索树算法(BST)
原文:图解:二叉搜索树算法(BST) 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!“岁月极美,在于它必然的流逝”“春花 秋月 夏日 冬雪”— ...
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- Elasticsearch java api 基本搜索部分详解
文档是结合几个博客整理出来的,内容大部分为转载内容.在使用过程中,对一些疑问点进行了整理与解析. Elasticsearch java api 基本搜索部分详解 ElasticSearch 常用的查询 ...
- Java实现 LeetCode 701 二叉搜索树中的插入操作(遍历树)
701. 二叉搜索树中的插入操作 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树. 返回插入后二叉搜索树的根节点. 保证原始二叉搜索树中不存在新值. 注意,可能存在多种有效的插入 ...
- Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
700. 二叉搜索树中的搜索 给定二叉搜索树(BST)的根节点和一个值. 你需要在BST中找到节点值等于给定值的节点. 返回以该节点为根的子树. 如果节点不存在,则返回 NULL. 例如, 给定二叉搜 ...
- Java实现 LeetCode 501 二叉搜索树中的众数
501. 二叉搜索树中的众数 给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素). 假定 BST 有如下定义: 结点左子树中所含结点的值小于等于当前结点的值 结点 ...
- Java实现 LeetCode 450 删除二叉搜索树中的节点
450. 删除二叉搜索树中的节点 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变.返回二叉搜索树(有可能被更新)的根节点的引 ...
- Java实现 LeetCode 230 二叉搜索树中第K小的元素
230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. ...
- Velocity魔法堂系列二:VTL语法详解
一.前言 Velocity作为历史悠久的模板引擎不单单可以替代JSP作为Java Web的服务端网页模板引擎,而且可以作为普通文本的模板引擎来增强服务端程序文本处理能力.而且Velocity被移植到不 ...
随机推荐
- POJ2187Beauty Contest
http://poj.org/problem?id=2187 题意 :有一个农场有N个房子,问最远的房子相距多少距离 . 思路 :凸包,旋转卡壳,通过寻找所有的对锺点,找出最远的点对. #includ ...
- poj The Clocks 高斯消元
由于数据量不大,所以这题有很多解法. 我用的是高斯消元化为逆矩阵解决的…… 代码如下: #include<stdio.h> #include<iostream> using n ...
- Linux中的栈:用户态栈/内核栈/中断栈
http://blog.chinaunix.net/uid-14528823-id-4136760.html Linux中有多种栈,很容易弄晕,简单说明一下: 1.用户态栈:在进程用户态地址空间底部, ...
- js 中中括号,大括号使用详解
一.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数.如:var LangShen = {"Name":"Langshen",&quo ...
- nginx 详解
#运行用户 #user nobody; #启动进程,通常设置成和cpu的数量相等或者2倍于cpu的个数(具体结合cpu和内存).默认为1 worker_processes 1; #全局的错 ...
- 123. Best Time to Buy and Sell Stock III
题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...
- Windows使用virtualenv搭建flask开发环境
virtualenv: VirtualEnv用于在一台机器上创建多个独立的Python虚拟运行环境,多个Python环境相互独立,互不影响,它能够: 在没有权限的情况下安装新套件 不同应用可以使用不同 ...
- bzoj1061: [Noi2008]志愿者招募
线性规划与费用流.http://www.cnblogs.com/iiyiyi/p/5616080.html.数组范围开错了!!!然后2.31-1=0x7fffffff!=0x7f7f7f7f. 开始以 ...
- poj 2503 快排+二分
..] of string; i,n,l,r,mid:longint; s:string; procedure qsort(h,l:longint); var i,j:longint; temp,m: ...
- Spring3中用注解直接注入properties中的值
在bean(可是controller, service, dao等了)中,使用@Value注解: @Service public class TestService{ @Value("${s ...