二叉排序树又称二叉查找树,它是一种对排序和查找都很有用的特殊二叉树。
二叉树的定义:二叉树或者是一颗空树,或者是具有下列性质的二叉树:
1.若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
2.若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
3.它的左右子树也分别为二叉排序树。
简单的说就是(左 < 根 < 右)
二叉排序树的创建:从空的二叉排序树开始,每输入一个结点,经过查找操作,将新结点插入到当前二叉排序树的合适位置。
二叉排序树的插入:对于待插入的结点,根据二叉排序树的特性找到该结点合适的位置并插入。
二叉排序树的查询:对于带查询的结点,根据二叉排序树的特性从树根一直往下找,直到找到为止或者未找到。
二叉排序树的删除:
1.从树根开始查找待删结点,若树中不存在该结点,则不做任何操作。
2.若找到待删结点,设待删结点为d,则分3种情况考虑---d的左右子树均不空,d无左子树,d无右子树
a.左右子树均不空:在d的左子树中,找到最右边的结点p,然后将该节点放入d所在位置(相当于用p取代d,仔细想想就会发 现只有这个结点放入d,才会使整颗二叉排序树保持原有特性)
b.无右子树:只需将左子树接上去即可。
c.无左子树,只需将右子树接上去即可。
二叉排序树的中序遍历就是整个待排序序列的最终结果。
import java.util.Scanner;
/**
* 二叉排序树 (binary sort tree)
* 对于一个根节点,其左子树上所有节点的值都小于根节点的值
* 而右子树节点上的权值都大于根节点的权值
* @author tiny_spot
*/
public class BSTree {
static Scanner s = new Scanner(System.in);
public static int END_FLAG = 0x7fffffff;
public static void main(String []args) {
//System.out.println("结尾标志符:"+END_FLAG);
System.out.println("按ctrl+z结束输入....");
BSTNode root = createBST();
if(root == null)
System.out.println("二叉排序树为空!");
else {
inOrder(root);//中序输出
System.out.println();
//preOrder(root);
root = deleteBST(root, 17);
inOrder(root);
System.out.println();
root = deleteBST(root, 78);
inOrder(root);
}
s.close();
}
/**
* 创建二叉排序树
* @return 二叉树的根节点
*/
public static BSTNode createBST() {
int t;
BSTNode root = new BSTNode();
if(s.hasNext()) {
t = s.nextInt();
root.val = t;
while(s.hasNext()) {
t = s.nextInt();
insertBST(root, t);
}
}else return null;
return root;
}
/**
* 将节点插入二叉排序树
* @param root 二叉树的根节点
* @param n 待插入的值
*/
public static void insertBST(BSTNode root ,int n) {
if(root == null) {//如果为真,表明这是整棵树的根节点
root.val = n;
return ;
}
if(root.val > n) {
if(root.left == null) {
root.left = new BSTNode();
root.left.val = n;
return;
}
insertBST(root.left, n);
}else{//如果根节点的值小于等于n,则把n放到右子树上
if(root.right == null) {
root.right = new BSTNode();
root.right.val = n;
return;
}
insertBST(root.right, n);
}
}
/**
* 删除节点值为key的节点,并保持二叉树原有的特性
* 如果不存在节点值为key的节点,则什么都不做
* @param root 二叉树的根节点
* @param key 待删除的 值
* @return 返回树的根节点
*/
public static BSTNode deleteBST(BSTNode root ,int key) {
BSTNode p = root, q, f=null;
while(p != null) {//查找节点值为key的节点
if(p.val == key)
break;
f = p;
if(p.val > key)
p = p.left;
else p = p.right;
}
if(p == null)//表明树中没有key这个关键字
return root;
q = p; //此时p和q都是目标节点的引用
if(p.left!=null && p.right!=null) {//若被删节点左右子树均不为空 ,则删除该节点左子树中最右端节点,并将其值赋给p
BSTNode s = p.left;
while(s.right != null){//一直往左子树的右边找
q = s;//q为s的上一个节点
s = s.right;
}//出循环之后,s节点是没有右子树的!
p.val = s.val;//改变待删节点的值即表示删除它
if(p == q)//表示s节点为待删节点的左子树的根节点,此时s节点的父亲节点为p或q,这时s节点是否有左子树未知,所以将s的左子树重接至p的左子树
q.left = s.left;
else q.right = s.left;//p!=q 表示待删节点的左子树还有右孩子节点,此时s节点的父亲节点为q,所以需要用s的左子树重接q的右子树
s = null;//删除s节点
}else if(p.left != null) {//待删节点只有左子树,右子树为空
q = p.left;
p.val = q.val;
p.left = q.left;
p.right = q.right;
q = null;
}else if(p.right != null) {//待删节点只有右子树,左子树为空
q = p.right;
p.val = q.val;
p.left = q.left;
p.right = q.right;
q = null;
}else {//待删节点是叶子节点
if(f == null) { //f=null表明待删节点是树的分界点,并且这棵树没有左右子树
return null;
}else {
if(f.left.val == key)
f.left = null;
else f.right = null;
}
}
return root;
}
/**
* 中序遍历,其结果就是一个完整的排好序的序列
* @param root 二叉树的根节点
*/
public static void inOrder(BSTNode root) {
if(root == null)
return;
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
/**
* 前序遍历
* @param root 二叉树的根节点
*/
public static void preOrder(BSTNode root) {
if(root == null)
return ;
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
}
class BSTNode{
BSTNode left=null;
BSTNode right = null;
public int val;
}
// 45 24 53 12 37 93 2147483647
// 12 24 37 45 53 93 2147483647
// 46 24 12 53 -10 12 37 45 93 2147483647
// 53 17 78 9 65 45 87 23 87
// 5