本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于平衡二叉树(avl树)的相关知识,avl树本质上是带了平衡功能的二叉查找树,下面一起来看一下,希望对大家有帮助。
推荐学习:《java视频教程》
avl树的引入搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以下极端情况:
这样的二叉树搜索效率甚至比链表还低。在搜索二叉树基础上出现的平衡二叉树(avl树)就解决了这样的问题。当平衡二叉树(avl树)的某个节点左右子树高度差的绝对值大于1时,就会通过旋转操作减小它们的高度差。
基本概念avl树本质上还是一棵二叉搜索树,它的特点是:
本身首先是一棵二叉搜索树。每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。也就是说,avl树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。当插入一个节点或者删除一个节点时,导致某一个节点的左右子树高度差的绝对值大于1,这时需要通过左旋和右旋的操作使二叉树再次达到平衡状态。平衡因子(balancefactor)
一个结点的左子树与右子树的高度之差。avl树中的任意结点的bf只可能是-1,0和1。基础设计下面是avl树需要的简单方法和属性:
public class avltree <e extends comparable<e>>{ class node{ e value; node left; node right; int height; public node(){} public node(e value){ this.value = value; height = 1; left = null; right = null; } public void display(){ system.out.print(this.value + ); } } node root; int size; public int size(){ return size; } public int getheight(node node) { if(node == null) return 0; return node.height; } //获取平衡因子(左右子树的高度差,大小为1或者0是平衡的,大小大于1不平衡) public int getbalancefactor(){ return getbalancefactor(root); } public int getbalancefactor(node node){ if(node == null) return 0; return getheight(node.left) - getheight(node.right); } //判断一个树是否是一个平衡二叉树 public boolean isbalance(node node){ if(node == null) return true; int balancefactor = math.abs(getbalancefactor(node.left) - getbalancefactor(node.right)); if(balancefactor > 1) return false; return isbalance(node.left) && isbalance(node.right); } public boolean isbalance(){ return isbalance(root); } //中序遍历树 private void inprevorder(node root){ if(root == null) return; inprevorder(root.left); root.display(); inprevorder(root.right); } public void inprevorder(){ system.out.print(中序遍历:); inprevorder(root); }}
rr(左旋)往一个树右子树的右子树上插入一个节点,导致二叉树变得不在平衡,如下图,往平衡二叉树中插入5,导致这个树变得不再平衡,此时需要左旋操作,如下:
代码如下:
//左旋,并且返回新的根节点 public node leftrotate(node node){ system.out.println(leftrotate); node cur = node.right; node.right = cur.left; cur.left = node; //跟新node和cur的高度 node.height = math.max(getheight(node.left),getheight(node.right)) + 1; cur.height = math.max(getheight(cur.left),getheight(cur.right)) + 1; return cur; }
ll(右旋)往一个avl树左子树的左子树上插入一个节点,导致二叉树变得不在平衡,如下图,往平衡二叉树中插入2,导致这个树变得不再平衡,此时需要左旋操作,如下:
代码如下:
//右旋,并且返回新的根节点 public node rightrotate(node node){ system.out.println(rightrotate); node cur = node.left; node.left = cur.right; cur.right = node; //跟新node和cur的高度 node.height = math.max(getheight(node.left),getheight(node.right)) + 1; cur.height = math.max(getheight(cur.left),getheight(cur.right)) + 1; return cur; }
lr(先左旋再右旋)往avl树左子树的右子树上插入一个节点,导致该树不再平衡,需要先对左子树进行左旋,再对整棵树右旋,如下图所示,插入节点为5.
rl(先右旋再左旋)往avl树右子树的左子树上插入一个节点,导致该树不再平衡,需要先对右子树进行右旋,再对整棵树左旋,如下图所示,插入节点为2.
添加节点//添加元素 public void add(e e){ root = add(root,e); } public node add(node node, e value) { if (node == null) { size++; return new node(value); } if (value.compareto(node.value) > 0) { node.right = add(node.right, value); } else if (value.compareto(node.value) < 0) { node.left = add(node.left, value); } //跟新节点高度 node.height = math.max(getheight(node.left), getheight(node.right)) + 1; //获取当前节点的平衡因子 int balancefactor = getbalancefactor(node); //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的左子树上,此时需要进行右旋 if (balancefactor > 1 && getbalancefactor(node.left) >= 0) { return rightrotate(node); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树子树的右子树上,此时需要进行左旋 else if (balancefactor < -1 && getbalancefactor(node.right) <= 0) { return leftrotate(node); } //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的右子树上,此时需要先对左子树左旋,在整个树右旋 else if (balancefactor > 1 && getbalancefactor(node.left) < 0) { node.left = leftrotate(node.left); return rightrotate(node); } //balancefactor < -1 && getbalancefactor(node.left) > 0 //该子树不平衡且新插入节点(导致不平衡的节点)在右子树的左子树上,此时需要先对右子树右旋,再整个树左旋 else if(balancefactor < -1 && getbalancefactor(node.right) > 0) { node.right = rightrotate(node.right); return leftrotate(node); } return node; }
删除节点 //删除节点 public e remove(e value){ root = remove(root,value); if(root == null){ return null; } return root.value; } public node remove(node node, e value){ node retnode = null; if(node == null) return retnode; if(value.compareto(node.value) > 0){ node.right = remove(node.right,value); retnode = node; } else if(value.compareto(node.value) < 0){ node.left = remove(node.left,value); retnode = node; } //value.compareto(node.value) = 0 else{ //左右节点都为空,或者左节点为空 if(node.left == null){ size--; retnode = node.right; } //右节点为空 else if(node.right == null){ size--; retnode = node.left; } //左右节点都不为空 else{ node successor = new node(); //寻找右子树最小的节点 node cur = node.right; while(cur.left != null){ cur = cur.left; } successor.value = cur.value; successor.right = remove(node.right,value); successor.left = node.left; node.left = node.right = null; retnode = successor; } if(retnode == null) return null; //维护二叉树平衡 //跟新height retnode.height = math.max(getheight(retnode.left),getheight(retnode.right)); } int balancefactor = getbalancefactor(retnode); //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的左子树上,此时需要进行右旋 if (balancefactor > 1 && getbalancefactor(retnode.left) >= 0) { return rightrotate(retnode); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树子树的右子树上,此时需要进行左旋 else if (balancefactor < -1 && getbalancefactor(retnode.right) <= 0) { return leftrotate(retnode); } //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的右子树上,此时需要先对左子树左旋,在整个树右旋 else if (balancefactor > 1 && getbalancefactor(retnode.left) < 0) { retnode.left = leftrotate(retnode.left); return rightrotate(retnode); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树的左子树上,此时需要先对右子树右旋,再整个树左旋 else if(balancefactor < -1 && getbalancefactor(retnode.right) > 0) { retnode.right = rightrotate(retnode.right); return leftrotate(retnode); } return retnode; }
推荐学习:《java视频教程》
以上就是java数据结构之avl树详解的详细内容。