二叉排序树(BST)
任何一个节点, 左边的节点值都比他小,右边的都比他大,中序遍历得到的是从小到大的数列。
可以用来排序和快速查找。
1. 添加
从根节点向下寻找,比当前节点小就向左,比当前节点大就向右,直到最低端,然后称为新的叶子节点(没有孩子节点的节点)。
2. 查询
从根节点向下寻找,比当前节点小就向左,比当前节点大就向右,相等时就找到了
3. 删除(主要难点)
3种情况
1. 没有孩子节点
叶子节点可以直接删掉,用null代替其原来位置
2. 有一个孩子
用孩子节点代替自己。
3. 有两个孩子
用右孩子的最小叶子节点,或者左孩子的最大叶子节点代替自己,然后删掉那个叶子节点
本质就是找个跟自己中序遍历时挨着的节点代替自己,这样不会影响整体结构。
平衡二叉树(以后再整理=。=)的继承节点是找自己右孩子的左叶子节点,所以这里就用右孩子的左叶子节点代替了。
package tree;
public class BinarySortTree {
Node root;
public BinarySortTree(){
root = null;
}
//添加节点
public void add(int num){
if(root == null) {
root = new Node(num);
}
else{
Node n = new Node(num);
root.add(n);
}
}
//中序遍历 (按顺序从小到大)
public void show(){
if(root == null){
System.out.println("树为空");
}
else{
root.show();
}
}
//发现节点
public Node findNode(int num){
if(root == null){
System.out.println("树为空");
return null;
}
else{
return root.findNode(num);
}
}
//发现父节点
public Node findParentNode(int num){
if(root == null){
System.out.println("树为空");
return null;
}
else{
return root.findParentNode(num);
}
}
//发现以某个节点为根节点的子树的最小叶子节点(用来找继承者)
public Node findSubTreeMin(Node node){
//因为只是为了找最小,每个节点左边的都比他小,所以只遍历左边
//不过如果有重复值,按照插入的规则会在左边,会继续向左找,保证找到的是叶子节点。
if(node.left == null){
return node;
}
else{ //左子树存在,说明有更小的值,继续向左找
return findSubTreeMin(node.left);
}
}
//删除节点
public void delete(int num){
if(root == null){
System.out.println("树为空");
return;
}
else{
Node targetNode = findNode(num);
if (targetNode == null) {
System.out.println("没有发现目标节点");
return;
}
Node parentNode = findParentNode(num);
if (parentNode == null) { //没有父亲节点,说明是root
System.out.println("目标节点是root");
if(root.left != null && root.right == null){ //左节点不为空, 右节点为空
root = root.left;
return;
}
else if(root.left == null && root.right != null){ //左节点不为空, 右节点为空
root = root.right;
return;
}
else if(root.left == null && root.right == null){ //左右都为空
root = null;
return;
}
//3.两个孩子, 用左边最大的叶子节点或者右边最小的叶子节点代替自己 (这里写的是用右边最小的代替)
//**********注意,如果这里是用右边最小代替,插入的时候重复值要插在左边,不然会导致找到的不是叶子节点,出现问题。
//上面写的方法是发现子树的最小节点,这里是发现目标右边子树最小的节点,所以参数是root.right
if(root.left != null && root.right != null){
Node rightMinNode = findSubTreeMin(targetNode.right);
int temp = rightMinNode.value;
delete(temp);
root.value = temp;
}
}
else{ // target不是根节点
// 1. 叶子节点, 2.一个孩子, 3,两个孩子
//1. 叶子节点, 用null代替自己
if(targetNode.left == null && targetNode.right == null){ //左右都为空 (叶子节点)
//判断是父节点的左孩子还是右孩子,然后置空;
if(parentNode.left != null && parentNode.left == targetNode){
parentNode.left = null;
return;
}
else if(parentNode.right != null && parentNode.right == targetNode){
parentNode.right = null;
return;
}
}
//2.一个孩子, 用孩子代替自己
if(targetNode.left != null && targetNode.right == null){ //有左孩子没有右孩子,把左孩子放在自己当前位置
//判断是父节点的左孩子还是右孩子,然后放置
if(parentNode.left != null && parentNode.left == targetNode){
parentNode.left = targetNode.left;
return;
}
else if(parentNode.right != null && parentNode.right == targetNode){
parentNode.right = targetNode.left;
return;
}
}
if(targetNode.left == null && targetNode.right != null){ //有右孩子没有左孩子,把右孩子放在自己当前位置
//判断是父节点的左孩子还是右孩子,然后放置
if(parentNode.left != null && parentNode.left == targetNode){
parentNode.left = targetNode.right;
return;
}
else if(parentNode.right != null && parentNode.right == targetNode){
parentNode.right = targetNode.right;
return;
}
}
//3.两个孩子, 用左边最大的叶子节点或者右边最小的叶子节点代替自己 (这里写的是用右边最小的代替)
//上面写的方法是发现子树的最小节点,这里是发现目标右边子树最小的节点,所以参数是targetNode.right
if(targetNode.left != null && targetNode.right != null){
Node rightMinNode = findSubTreeMin(targetNode.right);
//判断是父节点的左孩子还是右孩子,然后放置
if(parentNode.left != null && parentNode.left == targetNode){
int temp = rightMinNode.value;
delete(temp);
parentNode.left.value = temp;
return;
}
else if(parentNode.right != null && parentNode.right == targetNode){
int temp = rightMinNode.value;
delete(temp);
parentNode.right.value = temp;
return;
}
}
}
}
}
public static void main(String[] args){
BinarySortTree bst = new BinarySortTree();
bst.add(5);
bst.add(4);
bst.add(6);
bst.add(2);
bst.add(8);
bst.add(3);
bst.add(9);
bst.add(1);
bst.add(7);
bst.add(5);
bst.add(4);
bst.add(6);
System.out.println("中序遍历");
bst.show();
System.out.println();
bst.delete(5); //删除一个节点
bst.show();
}
public class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value = value;
}
public void add(Node n){
if(n == null){
return;
}
else{
if(n.value <= this.value){ //相等的放在左边
if(this.left == null){
this.left = n;
}
else{
this.left.add(n);
}
}
else{ // >=
if(this.right == null){
this.right = n;
}
else{
this.right.add(n);
}
}
}
}//add end
public void show(){
if(this.left != null){
this.left.show();
}
System.out.print(this.value + " ");
if(this.right != null){
this.right.show();
}
}
public void delete(int num){
Node father = this;
Node child = null;
}
public Node findNode(int num){
Node n = null;
if(this.value == num){
return this;
}
else if(num < this.value && this.left != null){
return this.left.findNode(num);
}
else if(num >= this.value && this.right != null){
return this.right.findNode(num);
}
else{
return null;
}
}
public Node findParentNode(int num){
Node n = null;
if(this.left != null && this.left.value == num){ //num 是左孩子
return this;
}
else if(this.right != null && this.right.value == num){ //num 是右孩子
return this;
}
else if(num < this.value && this.left != null){// num不是孩子节点,且比当前节点小,继续向左寻找
return this.left.findParentNode(num);
}
else if(num >= this.value && this.right != null){// num不是孩子节点,且比当前节点大,继续向右寻找
return this.right.findParentNode(num);
}
else{ //进行不下去了,说明无法发现节点,返回null
System.out.println("父节点不存在");
return null;
}
}
}
}