import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class Tree {
private int n; //数据域
private Tree l; //左子树
private Tree r; //右子树
public Tree() {
root = null;
}
public Tree(int n, Tree l, Tree r) {
this.n = n;
this.l = l;
this.r = r;
}
public int getN() {
return n;
}
public Tree getL() {
return l;
}
public Tree getR() {
return r;
}
public void setN(int n) {
this.n = n;
}
public void setL(Tree l) {
this.l = l;
}
public void setR(Tree r) {
this.r = r;
}
public void add(Tree x) {
//如果添加的树的值小于根节点的值,加到左子树
if (x.n < n) { //x的数据域如果小于根节点的数据域
//判断左子树为空,则加在左子树
if (l == null) {
l = x;
}
//如果坐子树不为空,则将左子树作为树根,继续添加
else {
l.add(x);
}
} else {
//当需要增加的值大于根节点的值时,放右子树
//判断,当右子树为空时,将树直接赋值给右子树
if (r == null) {
r = x;
} else {
//不为空时,将右子树作为树根,继续添加
r.add(x);
}
}
}
//二叉树查找
/**
* (1)若二叉树排序树为空,则查找失败,返回空
* <p>
* (2)若二叉排序树非空,将给定的值x.n与x根节点的值比较:
* <p>
* ①如果x.n == x,返回T
* <p>
* ②如果x.n < x,递归查询T的左子树
* <p>
* ③如果x.n > x,递归查询T的右子树
*/
public Tree get(int n){
return get(root,n);
}
//递归的写法
public Tree get(Tree x, int n) {
//判断二叉树是否为空
if (x != null) {
//判断如果需要查找的树的数据与根结点的数据作比较
// 判断是左子树还是右子树,查到之后返回出去
if (x.n == n)
return x;
//如果x.n小于根节点的数据
if (n < x.n)
return get(x.l, n);
else
return get(x.r, n);
}
return null; //作用是结束方法吗?或者是一般是在确定了没有具体返回对象时返回null
}
//不用递归的方式查找
public Tree getTree(int n) {
//创建对象,将树根的结点赋值给了x(子树)
Tree x = root ;
//循环判断子树是否不为空
while(x != null){
//不为空,判断传过来的数据与子树的数据是否相等
if(x.n == n)
//如果相等,返回子树
return x;
//如果穿过来的数据小于子树的数据,放子树的左子树里面
else if(n < x.n)
//放左子树
x = x.l;
else
x = x.r;
}
return null;
}
public void inOrder(){
inOrder(root);
}
public void inOrder(Tree x){
if(x != null){
inOrder(x.l);
System.out.println(x.n+"");
inOrder(x.r);
}
}
public Tree(List<Integer> l){
creatTree(l);
}
//二叉树增加操作
//二叉排序树的插入是以查找为基础的,假设要插入的值为e,
// 那么从根结点往下查找,当树中不存在值等于e的结点时才插入。
// 新插入的结点一定是一个新添加的叶子结点,
// 并且是查找不成功时查找路径上访问的最后一个结点的左孩子或则右孩子结点。
/**
* (1)若二叉排序树为空,则待插入值e作为根的值插入到空树中。
*
* (2)若二叉排序树非空,则将e与根节点的值T.data进行比较:
*
* ①若e < T.data,则查找其左子树
*
* ②若e > T.data,则查找其右子树
*/
public void insertTree(int n){
//如果树为空,则直接把数据插入根节点
if(root == null){
//新建节点,把数据和子树为null赋值给root
root = new Node(n,null,null);
}
Tree x = root;
while(x != null ){
//输入的值和跟结点作比较,用于查询左子树
if(n < x.n){
//说明x.l就是要插入的位置
if(x.l == null){
//创建一个树赋值给x的左子树,将需要插入的数据n传给左子树
x.l = new Tree(n,null,null);
return;
}else{
//否则就一直去插入
x = x.l;
}
}
//查询右子树
else if(n > x.n){
//说明x.r就是要插入的位置
if(x.r == null){
//创建一个结点对象,并把要添加的数据和子树赋值给x.r
x.r = new Node(x,null,null);
return;
}
else{
x = x.r;
}
}
}
}
public void creatTree(List<Integer> l){
for(int i=0;i<l.size();i++){
insertTree(l.get(i));
}
}
//实现二叉树的删除操作
public void deleteTree(int n){
Tree x = root; //值等于x的结点
Tree f = null; //x的双亲结点 就是父节点
Tree s = null; //x的直接前驱(x的左子树中值最大的结点)
Tree q = null; //s的双亲结点 就是父节点
//寻找值等于o的结点
while(x != null) {
if (x.n == n)
break;
f = x;
//查找的值小于根节点的值,进去左子树
if (n < x.n)
//左子树
x = x.l;
else
//进右子树
x = x.r;
}
//没有值与n相等,证明没有结点
if(x == null)
return;
//s的父节点一开始可能是x
q = x;
//System.out.println("1");
//如果x的左右子树都不为空
if(x.l != null && x.r != null ){
s = x.l;
//寻找x左子树中值最大的结点,就是最右下的结点
while(s.r != null){
q = s;
s = s.r;
}
//此时s指向被删掉的结点的前驱
x.n = s.n;
if(q != x)
//重接q的右子树
q.r = s.l;
else
//重接q的左子树,如果s的双亲就为x的情况
q.l = s.l;
return;
}
//被删掉的结点的左子树为空,只需要处理右子树,这里涵盖了左右自述都为空的情况
//注意,如果左右自述都为空,那么x在这里会变味null
else if(x.l == null){
x = x.r;
}
else if(x.r == null){
x = x.l;
}
//System.out.println(f.n);
//被删除的结点为根
if(f == null)
root = x;
//如果被删掉结点时他的父节点的左节点
else if(q == f.l)
f.l = x;
//如果被删掉的结点时他的父节点的右结点
else
f.r = x;
}
public static void main(String[] args){
Integer[] a = new Integer[] {21,22,23,24,25,26};
ArrayList<Integer> l = new ArrayList<>(Array.asList(a));
Tree T = new Tree(l);
Tree.inOrder();
System.out.println();
int e = 22;
if(T.insertTree(n) != null){
System.out.println(T.insertTree(n).n);
}
if(T.get(n) != null){
System.out.println(T.get(n).n);
}
T.deleteTree(24);
T.inOrder();
}
}
平衡二叉树的增删改查
最新推荐文章于 2024-05-14 14:15:01 发布