二进制搜索树可以如下递归定义. 二进制搜索树可以是空的二进制树,也可以是满足以下属性的二进制树:
(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;
}
}
二进制搜索树的搜索过程从根节点开始. 如果查询关键字等于节点关键字,则它将命中;否则,如果查询关键字小于节点关键字,则输入“左子”;如果大于node关键字,则输入正确的儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字.
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 则返回
}
如果进行简单替换,则可能会遇到以下情况:
因此,我们必须在子树中选择一个合适的替换节点. 替换节点通常是右侧子树中的最小节点:
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);
}
}
}
测试功能:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-272663-1.html