二叉搜索树java实现
public class a {
public static void main(String[] args) {
SearchBinaryTree s = new SearchBinaryTree(null,0);
int[] array = new int[]{50, 30, 80, 20, 35, 34, 32, 40, 70, 75, 100};
for (int i = 0; i < array.length; i++) {
s.add(array[i]);
}
//二叉搜索树 中序遍历
inorder(s.root);
s.delete(70);
System.out.println();
inorder(s.root);
}
public static void inorder(Node root) {
if (root != null) {
inorder(root.leftChild);
System.out.print(root.val+"-");
inorder(root.rightChild);
}
}
}
class SearchBinaryTree{
public Node root;
private int size;
public SearchBinaryTree(Node root, int size) {
this.root = root;
this.size = size;
}
public boolean add(int val) {
//先判断父节点是否初始化
if (root == null) {
root = new Node(val);
size++;
return true;
}
//父节点已经初始化 则需要找到需要插入的合适的父节点
Node node = findFatherNode(root,val);
Node childNode = new Node(val);
//找到父节点之后 与父节点值比较
if (val < node.val) {
node.leftChild = childNode;
childNode.parent = node;
} else if (val > node.val) {
node.rightChild = childNode;
childNode.parent = node;
} else {
//相等
return false;
}
size++;
return true;
}
/**
* 找到精要插入的合适的父节点
* 递归写法,需要分别对节点的左右子树,先写临界返回
* 临界返回有几种情况,
* 1、父节点为空
* 2、父节点的左右子树分别为空
* 3、父节点就是叶子节点
* 4、插入节点值与父节点相等
*/
public Node findFatherNode(Node node, int val) {
//1、父节点为空
if (node== null) {
return node;
}
//2、父节点的左右子树分别为空
if (val < node.val && node.leftChild == null) {
return node;
}
if (val > node.val && node.rightChild == null) {
return node;
}
//3、父节点就是叶子节点
if (node.leftChild == null && node.rightChild == null) {
return node;
}
//左右子树分别递归遍历
if (val < node.val && node.leftChild != null) {
return findFatherNode(node.leftChild, val);
} else if (val > node.val && node.rightChild != null) {
return findFatherNode(node.rightChild, val);
} else {
//4、插入节点值与父节点相等
return node;
}
}
//循环迭代版本
public boolean put(int val) {
//先判断父节点是否初始化
if (root == null) {
root = new Node(val);
size++;
return true;
}
Node temp = root;
Node fatherNode;
int t;
do {
fatherNode = temp;
t =temp.val - val;
if (t > 0) {
temp = temp.leftChild;
} else if (t < 0) {
temp = temp.rightChild;
} else {
temp.val = val;
return false;
}
} while (temp != null);
Node childNode = new Node(fatherNode, val);
if (t > 0) {
fatherNode.leftChild = childNode;
} else if (t < 0) {
fatherNode.rightChild = childNode;
}
return true;
}
//删除节点
/**
* 删除节点有几种情况
* 1、删除的节点没有左右子节点
* 2、删除的节点只有左节点,没有右节点
* 3、删除的节点只有右节点,没有左节点
* 4、删除的节点既有左节点,又有右节点
* 针对第四种情况,需要找到该节点的后继节点,将此节点替换为后继节点
* 后继节点 :大于该节点值得所有节点集合中值最小的那个节点,即为后继节点,当然,也有可能不存在后继节点。
* 如果后继节点存在的情况下,它一定在其(右子树的左子节点中)(没有右子树的话可能是右子节点)
* 后继节点有一个特点,因为他大于某一个节点的最小值,所以他一定没有左子节点,所以针对第四种情况,先将后继节点与要删除的
* 节点替换,然后删除后继节点(后继节点没有左子节点,跟1、3种情况是一样,直接删除)
*/
public boolean delete(int val) {
Node node = getNode(val);
if (node == null) {
return Boolean.FALSE;
}
//第四种情况,左右节点都存在
if (node.leftChild != null && node.rightChild != null) {
//找到后继节点 将该节点替换为后继节点
Node successor = getSuccessor(node);
//值替换
node.val = successor.val;
node = successor;
}
//注意 这个时候后继节点还没删除 node此时就是后继节点
//下面就是相当于删除某一个节点 ,可能是1、2、3情况
Node child;
if (node.leftChild != null ) {
child = node.leftChild;
} else {
child = node.rightChild;
}
if (child != null) {
child.parent = node.parent;
}
//如果要删除节点的父节点为空,则要删除父节点
if (node.parent == null) {
this.root = child;
} else if (node == node.parent.leftChild) {
node.parent.leftChild = child;
} else if (node == node.parent.rightChild) {
node.parent.rightChild = child;
}
return Boolean.TRUE;
}
public Node getNode(int val) {
if (root == null) return null;
Node temp = root;
do {
if (val > temp.val) {
temp = temp.rightChild;
} else if (val < temp.val) {
temp = temp.leftChild;
} else {
return temp;
}
} while (temp != null);
return null;
}
/**
* 获取后继节点
* 1、先判断该节点有没有右子树,如果有,则从右节点的左子树中寻找后继节点,没有则进行下一步
* 2、
* @param node
* @return
*/
public Node getSuccessor(Node node) {
if (node == null) return null;
//后继节点存在于右子树中
Node p = node.rightChild;
if (p != null) {
while(p.leftChild != null) {
p = p.leftChild;
}
return p;
}
//如果该节点没有右子节点,则从其父节点中,祖父节点的右子树中寻找
//则查找"x的最低的父结点,并且该父结点要具有左孩子(最低的父节点)
//目标节点是存在与后继节点的左子树中,如下,找4的后继节点
//4 没有有子树,可以从他的父节点中找,但是4又是其父节点的右孩子,比父节点大,不符合后继节点要求,继续向上找
//直到找到父节点为左孩子位置,这样该父节点的值就一定小于它的父节点,而且目标节点是存在于它的子孩子中的
//这样即可找到后继节点
/**
* 6
* / \
* 1 7
* \
* 5
* /
* 3
* / \
* 2 4
* /
* 3.5
*/
while (node.parent != null && node == node.parent.rightChild) {
node = node.parent;
}
return node.parent;
}
/**
* 将子节点替换为父节点
* @param fatherNode
* @param childNode
*/
public void transplant(Node fatherNode, Node childNode) {
/*
需要判断父节点是否为root节点
如果父节点不是root节点,需要判断父节点是左子节点还是右子节点,
这样才能准确将childNode放到准确位置
*/
//父节点的父节点为空的话 就是root节点
if (fatherNode.parent == null) {
this.root = childNode;
} else if (fatherNode.parent.leftChild == fatherNode) {
fatherNode.parent.leftChild = childNode;
} else if (fatherNode.parent.rightChild == fatherNode) {
fatherNode.parent.rightChild = childNode;
}
if (childNode != null) {
childNode.parent = fatherNode.parent;
}
}
}
class Node{
Node parent;
Node leftChild;
Node rightChild;
int val;
public Node(Node parent, Node leftChild, Node rightChild, int val) {
this.parent = parent;
this.leftChild = leftChild;
this.rightChild = rightChild;
this.val = val;
}
public Node(int val){
this(null,null,null,val);
}
public Node(Node node,int val){
this(node,null,null,val);
}
}