欢迎使用CSDN-markdown编辑器
来源:互联网 发布:seo搜索排名优化怎么 编辑:程序博客网 时间:2024/06/05 16:45
二叉平衡树
说起这个树,我找了整整两天的时间,刚开始考虑的不周全,然后就一直该一直该,一直加一直加。
定义:
它是一颗空疏或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
二叉查找树的定义:
1、若左子树不为空,那么左子树所有结点的值小于均小于他的根结点的值
2、若右子树不为空,那么右子树的所有结点的值大于根结点的值
3、左右子树也分别为二叉查找树(排序树)
4、没有键值相当的结点
如果不知道二叉查找树了请看我上篇文章(格式不太好)
现在二叉查找树添加的源码:
在这里我定义了root,opRoot两个,root主要是根结点,方便以后去操作,opRoot主要是操作树的。
// 插入元素 public void insert(T t){ if(opRoot == null){ root.setT(t); opRoot = root; return ; } opRoot = root ; Node<T> node = new Node<T>(); node.setT(t); insert(opRoot , node) ; } // 插入值 private void insert(Node<T> opRoot, Node<T> node) { if(opRoot.getT().compareTo(node.getT()) > 0){ if(opRoot.getLeft() != null){ insert(opRoot.getLeft() , node ) ; }else { opRoot.setLeft(node); node.setParent(opRoot); } } if(opRoot.getT().compareTo(node.getT()) < 0){ if(opRoot.getRight() != null){ insert(opRoot.getRight() , node) ; }else { opRoot.setRight(node); node.setParent(opRoot); } } }
值已经插进去了,现在我们要判断这四种情况:
1、 在结点x的左孩子的左子树中插入元素(左左)
2、 在结点x的左孩子的右子树中插入元素(左右)
3、 在结点x的右孩子的左子树中插入元素(右左)
4、 在结点x的右孩子的右子树中插入元素(右右)
括号里这些代表有,没写的代表下层没有
首先看第一种情况:
我是这样考虑的,换位置,把第一个左换到上面,然后把第一个上面的放到有下面,注意:需要断开的一定要断开。
第四种情况,有类似第一种:
类似于上面那种,也是交换位置
还有一个leftOrRight这个类
这里是段开父类之后,然后下面的那个元素指向父类元素
第二种左右,也是交换位置
把最上面的和最下面的交换位置就行,把4放到5的位置,把5放到4的右子树
第三种右左
把四和三交换位置,然后把3放到4的左子树
最后一个root.setParent(null),防止操作到根元素,忘记把根的父给清除了。
上面这段代码也是判断父类的到底该左子树设置还是右子树设置。
接下来,还要考虑这种:
左边是第一次按照上面那样插入,留下的病根,右边左转一次的情况,这里还有右转,直到达到预期效
下面代码弄了好多次都不型,只能这样了,作用是判断左右的深度差师傅大于1.
private void leftAndRightBalance(Node opRoot) {
int left = treeDepth(opRoot.getLeft()) ;
int right = treeDepth(opRoot.getRight()) ;
if(left - right > 1){
rightxuanzhuan(opRoot);
return ;
}
if(right - left > 1){
leftxuanzhuan(opRoot);
return ;
}
底下是右旋转旋转一次
// 这里是左旋转的
private void rightxuanzhuan(Node opRoot) {
Node parent = opRoot.getParent();
Node left = opRoot.getLeft();
Node right = opRoot.getRight();
Node rightLeft = findLeft(right);
if(rightLeft.getT().compareTo(right.getT()) == 0){
rightLeft = null ;
}
newxuanzhuan(rightLeft);
left.setParent(parent);
if(parent != null){
parent.setLeft(left);
}else {
root = left ;
left.setParent(null);
}
if(rightLeft != null){
rightLeft.setLeft(left.getLeft());
if(left.getLeft()!=null){
left.getLeft().setParent(rightLeft);
}
}else{
opRoot.setLeft(left.getRight());
if(left.getRight() != null){
left.getRight().setParent(opRoot);
}
}
left.setRight(opRoot);
zaipanduan(left)
左旋转一次
private void leftxuanzhuan(Node opRoot) {
Node parent = opRoot.getParent();
Node right = opRoot.getRight();
Node rightleft = findLeft(right);
newxuanzhuan(rightleft);
right.setParent(parent);
if(parent != null){
parent.setRight(right);
}else{
root = right;
}
if(rightleft != null){
rightleft.setLeft(opRoot);
opRoot.setParent(rightleft);
}else{
right.setLeft(opRoot);
opRoot.setParent(right);
}
opRoot.setRight(null);
zaipanduan(right);
}
// 为上面这两个类提供的旋转
private void newxuanzhuan(Node rightleft) {
if(rightleft == null){
return ;
}
Node parent = rightleft.getParent();
if(parent == null || parent.getRight() != null){
return ;
}
rightleft.setParent(parent.getParent());
if(parent.getParent().getLeft() != null && parent.getParent().getLeft().getT().compareTo(parent.getT()) == 0){ parent.getParent().setLeft(parent.getLeft()); }else{ parent.getParent().setRight(parent.getLeft()); } rightleft.setRight(parent); parent.setParent(rightleft); parent.setLeft(null);}
作用是为上面两个方法提供旋转
下面这个是再进去,判断是否合理
private void zaipanduan(Node left) {
if(left != null && left.getLeft() != null){
zaipanduan(left.getLeft());
}
if(left !=null && left.getRight() != null){
zaipanduan(left.getRight());
}
zaipanduandigui(left);
}
private void zaipanduandigui(Node left){
xuanzhuanshu(left);
}
接下来给你们源码看,在这我建议你一步一步来,每一种你考虑考虑,然后把代码进一步优化
public void insert(T t) {
if (root.getT() == null) {
root.setT(t);
size++;
return;
}
opRoot = root;
Node node = new Node();
node.setT(t);
insert(opRoot, node);
size++;
}
private void insert(Node<T> opRoot, Node<T> node) { if (opRoot.getT().compareTo(node.getT()) > 0) { if (opRoot.getLeft() != null) { insert(opRoot.getLeft(), node); } else { opRoot.setLeft(node); node.setParent(opRoot); xuanzhuanshu(node); } } if (opRoot.getT().compareTo(node.getT()) < 0) { if (opRoot.getRight() != null) { insert(opRoot.getRight(), node); } else { opRoot.setRight(node); node.setParent(opRoot); xuanzhuanshu(node); } }}/* * 添加的时候有四种判断方式。 第一种是左左 第二种是右右 第三种是左右 第四种是右左 */private void xuanzhuanshu(Node<T> node) { Node<T> parent = null; // 判断,是否右父父(爷爷元素) if (node.getParent() != null && node.getParent().getParent() != null) parent = node.getParent().getParent(); if (parent == null) { return; } // 连续左左为空,右右有元素 if (parent.getLeft() == null && node.getParent().getLeft() == null) { if (parent.getParent() != null) { leftOrRight(parent.getParent(), node.getParent()); node.getParent().setParent(parent.getParent()); node.getParent().setLeft(parent); } else { node.getParent().setLeft(parent); root = node.getParent(); } parent.setParent(node.getParent()); parent.setRight(null); } // 连续左左有元素,右右为空 if (parent.getRight() == null && node.getParent().getRight() == null) { if (parent.getParent() != null) { leftOrRight(parent.getParent(), node.getParent()); node.getParent().setParent(parent.getParent()); node.getParent().setRight(parent); } else { node.getParent().setRight(parent); root = node.getParent(); } parent.setParent(node.getParent()); parent.setLeft(null); } // 下面是右空,然后在左空 if (parent.getRight() == null && node.getParent().getLeft() == null) { if (parent.getParent() != null) { leftOrRightNoOnOne(parent.getParent(), node); node.setParent(parent.getParent()); node.setLeft(parent.getLeft()); parent.getLeft().setParent(node); parent.getLeft().setRight(null); node.setRight(parent); parent.setParent(node); parent.setLeft(null); } else { root = node; node.setRight(parent); parent.setParent(node); parent.setLeft(null); node.setLeft(node.getParent()); node.getParent().setParent(node); node.getParent().setRight(null); } } // 左空,右空 if (parent.getLeft() == null && node.getParent().getRight() == null) { if (parent.getParent() != null) { leftOrRightNoOnOne(parent.getParent(), node); node.setParent(parent.getParent()); node.setRight(parent.getRight()); parent.getRight().setParent(node); parent.getRight().setLeft(null); node.setLeft(parent); parent.setParent(node); parent.setRight(null); } else { root = node; node.setLeft(parent); parent.setParent(node); parent.setRight(null); node.setRight(node.getParent()); node.getParent().setParent(node); node.getParent().setLeft(null); } } root.setParent(null); opRoot = root ; leftAndRightBalance(opRoot);}// 这个是用来检查左右方法平衡不平衡,两边的深度差是否小于等于1,如果大于1了,根据方向旋转;private void leftAndRightBalance(Node<T> opRoot) { int left = treeDepth(opRoot.getLeft()) ; int right = treeDepth(opRoot.getRight()) ; if(left - right > 1){ rightxuanzhuan(opRoot); return ; } if(right - left > 1){ leftxuanzhuan(opRoot); return ; }}// 这里是左旋转的private void rightxuanzhuan(Node<T> opRoot) { Node<T> parent = opRoot.getParent(); Node<T> left = opRoot.getLeft(); Node<T> right = opRoot.getRight(); Node<T> rightLeft = findLeft(right); if(rightLeft.getT().compareTo(right.getT()) == 0){ rightLeft = null ; } newxuanzhuan(rightLeft); left.setParent(parent); if(parent != null){ parent.setLeft(left); }else { root = left ; left.setParent(null); } if(rightLeft != null){ rightLeft.setLeft(left.getLeft()); if(left.getLeft()!=null){ left.getLeft().setParent(rightLeft); } }else{ opRoot.setLeft(left.getRight()); if(left.getRight() != null){ left.getRight().setParent(opRoot); } } left.setRight(opRoot); zaipanduan(left);}private void zaipanduan(Node<T> left) { if(left != null && left.getLeft() != null){ zaipanduan(left.getLeft()); } if(left !=null && left.getRight() != null){ zaipanduan(left.getRight()); } zaipanduandigui(left);}private void zaipanduandigui(Node<T> left){ xuanzhuanshu(left);}private void leftxuanzhuan(Node<T> opRoot) { Node<T> parent = opRoot.getParent(); Node<T> right = opRoot.getRight(); Node<T> rightleft = findLeft(right); newxuanzhuan(rightleft); right.setParent(parent); if(parent != null){ parent.setRight(right); }else{ root = right; } if(rightleft != null){ rightleft.setLeft(opRoot); opRoot.setParent(rightleft); }else{ right.setLeft(opRoot); opRoot.setParent(right); } opRoot.setRight(null); zaipanduan(right);}// 为上面这两个类提供的旋转private void newxuanzhuan(Node<T> rightleft) { if(rightleft == null){ return ; } Node<T> parent = rightleft.getParent(); if(parent == null || parent.getRight() != null){ return ; } rightleft.setParent(parent.getParent()); if(parent.getParent().getLeft() != null && parent.getParent().getLeft().getT().compareTo(parent.getT()) == 0){ parent.getParent().setLeft(parent.getLeft()); }else{ parent.getParent().setRight(parent.getLeft()); } rightleft.setRight(parent); parent.setParent(rightleft); parent.setLeft(null);}// 这个用于处理,不是连续的private void leftOrRightNoOnOne(Node<T> parent, Node<T> son) { if (parent.getLeft().getT().compareTo(son.getParent().getParent().getT()) == 0) { parent.setLeft(son); } else { parent.setRight(son); }}// 处理连续的private void leftOrRight(Node<T> parent, Node<T> son) { if (parent.getLeft() != null && parent.getLeft().getT() .compareTo(son.getParent().getT()) == 0) { parent.setLeft(son); } else { parent.setRight(son); }}
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- ASPX页面的运行机制
- 结构体内的指针
- Android 相关词汇总结
- 使用nvm安装nodejs到非系统盘
- 随想
- 欢迎使用CSDN-markdown编辑器
- golang内存管理
- ubuntu16.04安装jdk并配置
- hdu 1394 Minimum Inversion Number 【线段树查找】
- 常见面试题
- Ubuntu terminal中添加命令执行路径
- Linux基础命令详解之目录管理
- 编译src.zip Java1.8 src.zip
- Day 1