/**
* 节点的类
*
* @author Robert
* @date 2018-06-10
*/
public class Node {
private int data; //value值
private Node lchild; //左孩子
private Node rchild; //右孩子
public Node(){}
public Node(int data, Node lchild, Node rchild) {
super();
this.data = data;
this.lchild = lchild;
this.rchild = rchild;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getLchild() {
return lchild;
}
public void setLchild(Node lchild) {
this.lchild = lchild;
}
public Node getRchild() {
return rchild;
}
public void setRchild(Node rchild) {
this.rchild = rchild;
}
}
/**
* 二叉排序树(别称二叉查找树)
* 性质:
* (1)可以是空树
* (2)左子树的所有节点都小于根节点的值
* (3)右子树的所有节点都大于根节点的值
* (4)左右子树都也是二叉排序树
*
* 性能:
* +查找:最好O(log2(n))、最坏O(n)
* +插入、删除:经过查找找到节点位置,进行插入、删除
* @author Robert
* @date 2018-06-11
*/
public class BinarySortTree {
private Node root;//根节点
public BinarySortTree(){
this.root = null;
}
/**
* 查找二叉排序树中是否存在key值
* @param key
* @return
*/
public boolean searchBST(int key){
Node current = root;//以免影响到根节点
while(current!=null){
if(key == current.getData()){
return true;
} else if(key > current.getData()){
current = current.getRchild(); //推进循环
} else {
current = current.getLchild(); //推进循环
}
}
return false;
}
/**
* 二叉排序树插入节点
* @param key
* @return
*/
public boolean insertBST(int key){
Node rt = root;
/*
* 如果二叉树中存在key值,prev就是该key值对应的节点
* 否则prev就是寻找key值路径上的最后一个节点
*/
Node prev = null;
while(rt!=null){
prev = rt;
if(key == rt.getData()){
return false;
} else if(key > rt.getData()){
rt = rt.getRchild(); //推进循环
} else {
rt = rt.getLchild(); //推进循环
}
}
Node newNode = new Node(key,null,null);
//prev就是插入节点的父节点
if(root == null){
root = newNode;
}else if(key < prev.getData()){
prev.setLchild(newNode);
}else {
prev.setRchild(newNode);
}
return true;
}
/**
* 删除节点的三种情况:
* (1)要删除的事叶子节点,只需要将它的双亲节点的指向为空
* (2)要删除节点只有左子树或者右子树,直接让左子树或者右子树替代它
* (3)要删除的节点既有左子树,又有右子树(两种方法)
* ①用左子树的最大的那个小于根节点的值替代它,重接那个节点的左子树
* ②用右子树的最小的那个大于根节点的值替代它,重接那个节点的右子树
*/
/**
* 查找需要删除的节点
* @param root
* @param key
* @return
*/
public void deleteBST(Node rt,int key){
//初始删除的参数为根节点和要删除的key节点
if(rt != null){
if(rt.getData() == key){
deleteNode(rt);
}else if(rt.getData() > key){
deleteBST(rt.getLchild(),key);
}else{
deleteBST(rt.getRchild(),key);
}
}
}
/**
* 实际的删除节点操作
* @param node
* @return
*/
public void deleteNode(Node node){
Node temp = null;
Node tNode = null;
if(node.getLchild() == null && node.getRchild() == null){ //叶子节点
temp = findParentNode(root, node);
if(temp.getLchild() == node){
temp.setLchild(null);
} else {
temp.setRchild(null);
}
}else if(node.getLchild() != null && node.getRchild() == null){ //左子树不为空,右子树为空
temp = findParentNode(root, node);
if(temp.getLchild() == node){
temp.setLchild(node.getLchild());
} else {
temp.setRchild(node.getLchild());
}
}else if(node.getLchild() == null && node.getRchild() != null){ //左子树为空,右子树不为空
temp = findParentNode(root, node);
if(temp.getLchild() == node){
temp.setLchild(node.getRchild());
} else {
temp.setRchild(node.getRchild());
}
}else{ //左右子树都不为空
temp = getMaxNode(node.getLchild());
tNode = findParentNode(node.getLchild(), temp);
//将要删除的节点更换成temp的key值,然后真正删除的是temp节点
node.setData(temp.getData());
//处理temp节点的左子树问题(两种情况)
// * node -> *
// / \ / \
// node,tNode-> * * tNode-> * *
// / \ / \
// temp-> * * * * <- temp
// / /
// * *
if(tNode == node){
tNode.setLchild(temp.getLchild());
}else{
tNode.setRchild(temp.getLchild());
}
}
}
/**
* 查找节点node的父节点
* @param root
* @param node
* @return
*/
public Node findParentNode(Node rt,Node node){
Node result = null;
int key = node.getData();
//当前遍历的节点->next.value == key ,则该节点就是key值节点的父节点
while(rt != null){
if(rt.getLchild() != null && rt.getLchild().getData() == key){
return result = rt;
}else if(rt.getRchild() != null && rt.getRchild().getData() == key){
return result = rt;
}else if(rt.getData() > key){
rt = rt.getLchild();
}else if(rt.getData() < key){
rt = rt.getRchild();
}
}
return result;
}
/**
* 得到二叉排序树最小值的节点
* 二叉排序树的最小值永远是最左边的节点,如果存在的话
* @param root
* @return
*/
public Node getMinNode(Node root){
if(root == null){
return null;
}
if(root.getLchild() == null){
return root;
}else{
return getMinNode(root.getLchild());
}
}
/**
* 得到二叉排序树最大值的节点
* 二叉排序树的最大值永远是最右边的节点,如果存在的话
* @param root
* @return
*/
public Node getMaxNode(Node root){
if(root == null){
return null;
}
if(root.getRchild() == null){
return root;
}else{
return getMaxNode(root.getRchild());
}
}
/**
* 创建一棵BST树
* @param array
* @param n
*/
public void createBST(int[] array,int n){
for(int i=0;i<n;i++){
insertBST(array[i]);
}
}
/**
* 中序遍历
* @param root
*/
public void MidOrderTraverse(Node root){
if(root!=null){
MidOrderTraverse(root.getLchild());
System.out.print(root.getData() + " ");
MidOrderTraverse(root.getRchild());
}
}
//测试main函数
public static void main(String[] args){
int[] array = {17,12,19,10,15,18,20,8,11,13,16,14};
BinarySortTree bst = new BinarySortTree();
System.out.println("=========:正常二叉排序树");
bst.createBST(array, array.length);
bst.MidOrderTraverse(bst.root);
System.out.println();
System.out.println("=========:删除节点的二叉排序树");
bst.deleteBST(bst.root, 15);
bst.MidOrderTraverse(bst.root);
//System.out.println(bst.searchBST(5));
}
}
之后添加
①在节点Node实类上多添一个指向父节点的属性
②在BinarySortTree多添加一个tempNode作为全局变量来存searchBST()方法的返回值
修改过的方法
①deleteBST()
②deleteNode()
/**
* 节点的实类
* @author Robert
* @date 2018-06-12
*/
public class AdcNode {
private int data;
private AdcNode lchild;
private AdcNode rchild;
private AdcNode parent; //新添的父节点指向
public AdcNode(){
}
public AdcNode(int data) {
super();
this.data = data;
this.lchild = null;
this.rchild = null;
this.parent = null;
}
public AdcNode(int data, AdcNode lchild, AdcNode rchild, AdcNode parent) {
super();
this.data = data;
this.lchild = lchild;
this.rchild = rchild;
this.parent = parent;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public AdcNode getLchild() {
return lchild;
}
public void setLchild(AdcNode lchild) {
this.lchild = lchild;
}
public AdcNode getRchild() {
return rchild;
}
public void setRchild(AdcNode rchild) {
this.rchild = rchild;
}
public AdcNode getParent() {
return parent;
}
public void setParent(AdcNode parent) {
this.parent = parent;
}
}
/**
* @author Robert
* @date 2018-06-12
*/
public class AdvanceBST {
private AdcNode root;
private AdcNode tempNode; //临时节点
public AdvanceBST(){
this.root = null;
this.tempNode = null;
}
public boolean searchBST(int key){
AdcNode rt = root;
AdcNode tNode = null;
while(rt != null){
tNode = rt;
if(rt.getData() == key){
tempNode = tNode;
return true;
}else if(rt.getData() > key){
rt = rt.getLchild();
}else{
rt = rt.getRchild();
}
}
tempNode = tNode;
return false;
}
public boolean insertBST(int key){
if(!searchBST(key)){
AdcNode node = new AdcNode(key);
if(tempNode == null){ //BST的开始,根节点
root = node;
}else if(key > tempNode.getData()){
node.setParent(tempNode);
tempNode.setRchild(node);
}else{
node.setParent(tempNode);
tempNode.setLchild(node);
}
return true;
}
return false;
}
public void createBST(int[] a){
for(int i=0;i<a.length;i++){
insertBST(a[i]);
}
}
public void deleteBST(int key){
if(searchBST(key)){
deleteNode(tempNode);
}else{
System.out.println("没有该节点!");
}
}
public AdcNode getMaxNode(AdcNode root){
if(root == null){
return null;
}
if(root.getRchild() == null){
return root;
}else{
return getMaxNode(root.getRchild());
}
}
public void deleteNode(AdcNode node){
AdcNode temp = null;
AdcNode tNode = null;
if(node.getRchild() == null){ //右子树为空
temp = node.getParent();
if(temp.getLchild() == node){
temp.setLchild(node.getLchild());
} else {
temp.setRchild(node.getLchild());
}
}else if(node.getLchild() == null){ //左子树为空
temp = node.getParent();
if(temp.getLchild() == node){
temp.setLchild(node.getRchild());
} else {
temp.setRchild(node.getRchild());
}
}else{ //左右子树都不为空
temp = getMaxNode(node.getLchild());
tNode = temp.getParent();
node.setData(temp.getData());
if(tNode == node){
tNode.setLchild(temp.getLchild());
}else{
tNode.setRchild(temp.getLchild());
}
}
}
public void MidOrderTraverse(AdcNode rt){
if(rt!=null){
MidOrderTraverse(rt.getLchild());
System.out.print(rt.getData() + " ");
MidOrderTraverse(rt.getRchild());
}
}
public static void main(String[] args) {
int[] array = {17,12,19,10,15,18,20,8,11,13,16,14};
AdvanceBST bst = new AdvanceBST();
System.out.println("+++构建的BST树+++");
bst.createBST(array);
bst.MidOrderTraverse(bst.root);
System.out.println();
System.out.println("+++删除没有的节点+++");
bst.deleteBST(29);
bst.MidOrderTraverse(bst.root);
System.out.println();
System.out.println("+++删除有的节点+++");
bst.deleteBST(13);
bst.MidOrderTraverse(bst.root);
}
}