平衡二叉树(AVL树)
2013-11-28 12:46
525 查看
平衡二叉树的接口
平衡二叉树的节点类:
平衡二叉树的实现,参考《大话数据结构》的实现方法
package tree; /** * 平衡二叉树的操作 * * @author liangguojun * * @param <T> * 数据类型,该数据类型必须实现Comparable接口 */ public interface SortAVLTree<T extends Comparable<T>> { public static final int ASC_VALUE = 1; public static final int DESC_VALUE = 0; /** * 判断平衡二叉树是否为空 * * @return 平衡二叉树为空则返回true,否则返回false */ public boolean isEmpty(); /** * 求平衡二叉树的长度 * * @return 返回平衡二叉树的长度 */ public int getLength(); /** * 插入数据,插入数据后自动调整平衡二叉树 * * @param data * 数据元素 * @return 成功插入则返回true,否则返回false */ public boolean insert(T data); /** * 删除数据元素节点 * * @param data * 将要删除的数据元素节点 * @return 成功删除则返回true,否则返回false */ public boolean delete(T data); /** * 根据传入的参数,按升序或者降序遍历平衡二叉树 * * @param VALUE * 排序的控制参数 */ public void view(int VALUE); /** * 将数据元素move的数据改为data * * @param data * 替换的数据元素 * @param move * 被替换的数据元素 * @return 成功替换则返回true,否则返回false */ public boolean update(T data, T move); /** * 返回平衡二叉树的深度 * * @return 返回平衡二叉树的深度 */ public int getDept(); }
平衡二叉树的节点类:
package tree; /** * 平衡二叉树的节点类 * * @author liangguojun * * @param <T> * 数据类型 */ public class BirTreeNode<T> { private T data; private int bf; private BirTreeNode<T> lchild, rchild; public BirTreeNode(T data, int bf, BirTreeNode<T> lchild, BirTreeNode<T> rchild) { this.setData(data); this.setBf(bf); this.setLchild(lchild); this.setRchild(rchild); } public BirTreeNode(T data) { this(data, 0, null, null); } public BirTreeNode(T data, BirTreeNode<T> lchild, BirTreeNode<T> rchild) { this(data, 0, lchild, rchild); } public T getData() { return data; } public void setData(T data) { this.data = data; } public int getBf() { return bf; } public void setBf(int bf) { this.bf = bf; } public BirTreeNode<T> getLchild() { return lchild; } public void setLchild(BirTreeNode<T> lchild) { this.lchild = lchild; } public BirTreeNode<T> getRchild() { return rchild; } public void setRchild(BirTreeNode<T> rchild) { this.rchild = rchild; } public String toString() { return data.toString(); } }
平衡二叉树的实现,参考《大话数据结构》的实现方法
package tree; /** * 平衡二叉树的实现,参考《大话数据结构》的实现方法 * @author liangguojun * * @param <T> */ public class AVLSortTree<T extends Comparable<T>> implements SortAVLTree<T> { // 用于控制插入一个节点后判断树是否长高了。 private boolean taller = false; // 用于控制删除数据元素是树是否变矮了。 private boolean shorter = false; // 根节点 private BirTreeNode<T> root; // 左高 public static final int LH = 1; // 等高 public static final int EH = 0; // 右高 public static final int RH = -1; public AVLSortTree() { root = null; } // 返回根节点 public BirTreeNode<T> getRoot() { return root; } @Override public boolean isEmpty() { if (root == null) { return true; } return false; } /** * 求子树cur的长度 * * @param cur * 子树的根结点cur * @return 返回子树的长度 */ private int getLength(BirTreeNode<T> cur) { if (cur != null) { int lc = 0; int rc = 0; if (cur.getLchild() != null) lc = getLength(cur.getLchild()) + 1; if (cur.getRchild() != null) rc = getLength(cur.getRchild()) + 1; return lc + rc; } return 0; } @Override public int getLength() { if (root != null) return getLength(root) + 1; return 0; } /** * 右旋转的方法,当子树右旋转时,双亲不为空,则应该修改双亲的节点 * * @param cur * 需要旋转的子树根节点 * @param parent * 子树的双亲节点 */ private void rightRotate(BirTreeNode<T> cur, BirTreeNode<T> parent) { if (cur != null && cur.getLchild() != null) { // 旋转操作 BirTreeNode<T> L = cur.getLchild(); cur.setLchild(L.getRchild()); L.setRchild(cur); // 假如是根节点的话,则修改根节点 if (parent == null) { root = L; } else { // 假如cur的双亲parent的左孩子是cur,则修改左孩子,否则修改右孩子 if (parent != null && parent.getLchild() == cur) { parent.setLchild(L); } else if (parent != null && parent.getRchild() == cur) { parent.setRchild(L); } } } } /** * 左旋转的方法 * * @param cur * 需要左旋转的子树的根节点 * @param parent * 需要旋转子树的双亲节点 */ private void leftRotate(BirTreeNode<T> cur, BirTreeNode<T> parent) { if (cur != null && cur.getRchild() != null) { BirTreeNode<T> R = cur.getRchild(); cur.setRchild(R.getLchild()); R.setLchild(cur); // 假如是根节点的话,则修改根节点 if (parent == null) { root = R; } if (parent != null && parent.getLchild() == cur) { parent.setLchild(R); } else if (parent != null && parent.getRchild() == cur) { parent.setRchild(R); } } } /** * 对cur为根节点的二叉树做左旋转处理,方法结束后,根节点改变,如果cur右双亲节点,则应该修改双亲节点的孩子节点 * * @param cur * 二叉树的根节点 * @param parent * cur二叉树的双亲节点 */ private void leftBalance(BirTreeNode<T> cur, BirTreeNode<T> parent) { if (cur.getLchild() != null) { BirTreeNode<T> L = cur.getLchild(); BirTreeNode<T> Lr; switch (L.getBf()) { case LH: // 根节点左边高,左子树也是左边高,所以直接一次右旋转即可 cur.setBf(EH); L.setBf(EH); rightRotate(cur, parent); break; case RH: // 根节点左边高,而左子树是右边树高,所以要双旋转,使要旋转的树的符号一样 // 先对左子树左旋转,使左子树变成左边高 ,才能进行右旋转 Lr = L.getRchild(); // 修改平衡标志 switch (Lr.getBf()) { case LH: cur.setBf(RH); L.setBf(EH); break; case EH: cur.setBf(EH); L.setBf(EH); break; case RH: cur.setBf(EH); L.setBf(LH); break; } Lr.setBf(EH); // 先对最小不平衡树左旋 leftRotate(L, cur); // 对整棵树进行右旋 rightRotate(cur, parent); } } } /** * 对cur为根节点的二叉树做右旋转处理,方法结束后,根节点改变,如果cur右双亲节点,则应该修改双亲节点的孩子节点 * * @param cur * 需要进行右平衡处理的子树的根节点 * @param parent * cur的双亲节点 */ private void rightBalance(BirTreeNode<T> cur, BirTreeNode<T> parent) { if (cur.getRchild() != null) { BirTreeNode<T> R = cur.getRchild(); BirTreeNode<T> Rl; switch (R.getBf()) { // 旋转时的子树根节点右边高 case RH: cur.setBf(EH); R.setBf(EH); leftRotate(cur, parent); break; // 旋转时的子树的根节点左边高,跟根节点的符号不一样,要进行双旋转处理 case LH: Rl = R.getLchild(); switch (Rl.getBf()) { case LH: R.setBf(RH); cur.setBf(EH); break; case EH: R.setBf(EH); cur.setBf(EH); break; case RH: cur.setBf(LH); R.setBf(EH); break; } Rl.setBf(EH); rightRotate(R, cur); leftRotate(cur, parent); } } } /** * 插入节点的方法 * * @param cur * 被插入的节点 * @param parent * 插入节点的双亲 * @param data * 插入的数据元素 * @return 成功插入则返回true,否则返回false */ private boolean insert(BirTreeNode<T> cur, BirTreeNode<T> parent, T data) { if (data != null) { if (cur == null) { cur = new BirTreeNode<T>(data); // 插入节点作为双亲节点的左孩子还是右孩子 if (parent.getData().compareTo(cur.getData()) > 0) { parent.setLchild(cur); } if (parent.getData().compareTo(cur.getData()) < 0) { parent.setRchild(cur); } taller = true; } else { if (data.compareTo(cur.getData()) == 0) { taller = false; return false; } if (data.compareTo(cur.getData()) < 0) { // 递归调用插入函数,插入到左子树中 if (!insert(cur.getLchild(), cur, data)) { return false; } // 若插入成功插入左子树,且左子树长高,进行平衡度检查 if (taller) { switch (cur.getBf()) { // 原本左子树比右子树高,需要做左平衡处理 case LH: leftBalance(cur, parent); taller = false; break; // 原本左子树和右子树等高,现在因为左子树增高而树增高 case EH: cur.setBf(LH); taller = true; break; // 原本右子树比左子树高,现在左右子树等高 case RH: cur.setBf(EH); taller = false; break; } } } else { if (!insert(cur.getRchild(), cur, data)) return false; // 假如taller为ture,则成功插入右子树,且树已长高,进行平衡度检查 if (taller) { switch (cur.getBf()) { case LH: // 原本左子树比右子树高,现在左右子树等高 cur.setBf(EH); taller = false; break; case EH: // 原本左右子树等高,现因为右子树增高而树增高 cur.setBf(RH); taller = true; break; case RH: // 原本右子树比左子树高,需要做右平衡处理 rightBalance(cur, parent); taller = false; break; } } } } return true; } return false; } @Override public boolean insert(T data) { if (root == null) { root = new BirTreeNode<T>(data); this.taller = false; return true; } boolean tmp = insert(root, null, data); taller = false; return tmp; } /** * 删除节点时左平衡旋转处理 * * @param cur * 删除的树的根节点 * @param parent * 子树cur的双亲节点 */ private void leftBalance_div(BirTreeNode<T> cur, BirTreeNode<T> parent) { BirTreeNode<T> p1, p2; switch (cur.getBf()) { case LH: cur.setBf(EH); shorter = true; break; case EH: cur.setBf(RH); shorter = false; break; case RH: // // p1 = cur.getRchild(); switch (p1.getBf()) { case EH: p1.setBf(LH); cur.setBf(RH); shorter = false; leftRotate(cur, parent); break; case RH: p1.setBf(EH); cur.setBf(EH); shorter = true; rightRotate(cur, parent); break; case LH: // p2 = p1.getLchild(); if (p2.getBf() == EH) { cur.setBf(EH); p1.setBf(EH); } else if (p2.getBf() == RH) { cur.setBf(LH); p1.setBf(EH); } else { cur.setBf(EH); p1.setBf(-1); } p2.setBf(EH); rightRotate(p1, cur); shorter = true; // 这里要旋转吗? leftRotate(cur, parent); } } } /** * 删除节点时右平衡旋转处理 * * @param cur * 要旋转的子树的根节点 * @param parent * 子树的根节点的双亲节点 */ private void rightBalance_div(BirTreeNode<T> cur, BirTreeNode<T> parent) { BirTreeNode<T> p1, p2; switch (cur.getBf()) { case RH: cur.setBf(EH); shorter = true; break; case EH: cur.setBf(LH); shorter = false; break; case LH: p1 = cur.getLchild(); switch (p1.getBf()) { case EH: // 这里需要旋转 p1.setBf(RH); cur.setBf(LH); rightRotate(cur, parent); shorter = false; break; case LH: p1.setBf(EH); cur.setBf(EH); rightRotate(cur, parent); shorter = true; break; case RH: // p2 = p1.getRchild(); if (p2.getBf() == EH) { cur.setBf(EH); p1.setBf(EH); } else if (p2.getBf() == LH) { cur.setBf(RH); p1.setBf(EH); } else { cur.setBf(EH); p1.setBf(RH); } p2.setBf(EH); leftRotate(p1, cur); shorter = true; // 这里需要右旋吗? rightRotate(cur, parent); } } } /** * 删除节点cur,找到替代的节点r * * @param cur * 被删除的节点 * @param childParent * 替代节点的双亲节点 * @param r * 替代节点 * @param parent * 被删除节点的双亲节点 */ private void delete(BirTreeNode<T> cur, BirTreeNode<T> childParent, BirTreeNode<T> r, BirTreeNode<T> parent) { // 寻找替代节点的方法,替代的节点是被删除节点的左子树的最右的节点 // if (r.getRchild() == null) { if (parent != null) { if (parent.getLchild() == cur) { // 替代被删除的节点 parent.setLchild(r); // 被替代的节点的双亲节点修改孩子节点 if (childParent.getLchild() == r) { childParent.setLchild(r.getLchild()); } else if (childParent.getRchild() == r) { childParent.setRchild(r.getLchild()); } // 替代的节点接替被删除的左孩子和右孩子 r.setLchild(cur.getLchild()); r.setRchild(cur.getRchild()); } else if (parent.getRchild() == cur) { // 替代被删除的节点 parent.setRchild(r); // 被替代的节点的双亲节点修改孩子节点 if (childParent.getLchild() == r) { childParent.setLchild(r.getLchild()); } else if (childParent.getRchild() == r) { childParent.setRchild(r.getLchild()); } // 替代的节点接替被删除的左孩子和右孩子 r.setLchild(cur.getLchild()); r.setRchild(cur.getRchild()); } } else { root = r; if (childParent.getLchild() == r) { childParent.setLchild(r.getLchild()); } else if (childParent.getRchild() == r) { childParent.setRchild(r.getLchild()); } // 到这里为止,已经删除成功,接下来就要进行左子树的平衡处理了 // root.setLchild(cur.getLchild()); root.setRchild(cur.getRchild()); } shorter = true; } else if (r.getRchild() != null) { // 假如左子树的右子树还没到最后的右子树,则继续递归 delete(cur, r, r.getRchild(), parent); if (shorter) { // // rightBalance_div(r, root); } } } /** * 删除平衡二叉树的数据元素data * * @param data * 要删除的数据元素 * @param cur * 删除的子树的根节点 * @param parent * cur的双亲节点 * @return 成功删除则返回true,否则返回false */ private boolean delete(T data, BirTreeNode<T> cur, BirTreeNode<T> parent) { if (cur != null) { // 假如删除的数据元素比当前节点小 if (data.compareTo(cur.getData()) < 0) { delete(data, cur.getLchild(), cur); if (shorter) { // // leftBalance_div(cur, parent); } // 设置树变矮标志 // shorter = false; return true; } else if (data.compareTo(cur.getData()) > 0) { // 假如删除的数据元素比当前数据元素大 delete(data, cur.getRchild(), cur); if (shorter) { rightBalance_div(cur, parent); } // 设置树变矮的标志,这里不需要 // shorter = false; return true; } else { // 假如当前节点的右子树为空, 删除当前节点,重接左子树 if (cur.getRchild() == null) { if (parent.getLchild() == cur) { parent.setLchild(cur.getLchild()); } else if (parent.getRchild() == cur) { parent.setRchild(cur.getLchild()); } shorter = true; } else if (cur.getLchild() == null) { // 假如当前节点的左子树为空,删除当前节点,重接右子树 if (parent.getLchild() == cur) { parent.setLchild(cur.getRchild()); } else if (parent.getRchild() == cur) { parent.setRchild(cur.getRchild()); } shorter = true; } else { // 当左右子树都不为空的时候,寻找替代节点 // // delete(cur, cur, cur.getLchild(), parent); if (shorter) { leftBalance_div(cur, parent); } } return true; } } return false; } @Override public boolean delete(T data) { if (data != null) { return delete(data, root, null); } return false; } /** * 升序遍历平衡二叉树 * * @param cur * 需要遍历的树的根节点 */ private void viewASC(BirTreeNode<T> cur) { if (cur != null) { viewASC(cur.getLchild()); System.out.print(cur.getData() + " "); System.out.println("当前标志值为:" + cur.getBf() + "他的左孩子为:" + cur.getLchild() + "右孩子为:" + cur.getRchild()); viewASC(cur.getRchild()); } } /** * 降序遍历平衡二叉树 * * @param cur * 需要遍历的树的根节点 */ private void viewDESC(BirTreeNode<T> cur) { if (cur != null) { viewDESC(cur.getRchild()); System.out.print(cur.getData() + " "); viewDESC(cur.getLchild()); } } @Override public void view(int VALUE) { switch (VALUE) { case ASC_VALUE: viewASC(root); System.out.println(); break; case DESC_VALUE: viewDESC(root); System.out.println(); break; } } @Override public boolean update(T data, T move) { if (data != null && move != null) { this.delete(move); return this.insert(data); } return false; } /** * 求平衡二叉树的深度 * * @param cur * 子树的根节点 * @return 返回平衡二叉树的深度 */ private int getDept(BirTreeNode<T> cur) { if (cur != null) { int lc = getDept(cur.getLchild()) + 1; int rc = getDept(cur.getRchild()) + 1; return lc > rc ? lc : rc; } return 0; } @Override public int getDept() { return getDept(root); } /** * 清空整棵树 */ public void clear() { root = null; } /** * 先序遍历平衡二叉树,做测试用 * * @param cur * 子树的根节点 */ private void view(BirTreeNode<T> cur) { if (cur != null) { System.out.print(cur.getData() + " "); view(cur.getLchild()); view(cur.getRchild()); } } /** * 先序遍历平衡二叉树,做测试用。 */ public void view() { view(root); System.out.println(); } // 测试 public static void main(String[] args) { String[] a = { "J", "F", "I", "H", "C", "G", "B", "E", "D", "A" }; AVLSortTree<String> test = new AVLSortTree<>(); for (int i = 0; i < a.length; i++) { test.insert(a[i]); } // // System.out.println(test.insert("H")); // test.view(ASC_VALUE); // System.out.println("排序二叉树的深度 " + test.getDept()); // System.out.println("长度?:" + test.getLength()); // // System.out.println("是否为空:" + test.isEmpty()); // test.view(); System.out.println("初次尝试删除:::" + test.delete("A")); // System.out.println("根节点的标志值:" + test.getRoot().getBf()); // test.delete("J"); // test.delete("C"); // test.delete("D"); // test.delete("G"); test.insert("K"); System.out.println("初次尝试删除:::" + test.delete("B")); test.insert("L"); test.insert("M"); test.insert("N"); test.insert("O"); test.insert("P"); test.insert("Q"); test.insert("R"); test.insert("S"); test.insert("T"); test.insert("U"); test.insert("V"); test.insert("W"); test.insert("X"); // test.insert("A"); System.out.println("排序二叉树的深度 " + test.getDept()); System.out.println("根节点的数据元素为:" + test.getRoot().getData()); test.view(); test.view(ASC_VALUE); } }
相关文章推荐
- 平衡二叉树(AVL树的定义,旋转详解)
- 平衡二叉树(AVL树)
- 【原理思路】平衡二叉树(AVL树)原理
- 数据结构:平衡二叉树(AVL树)
- 数据结构之---C语言实现平衡二叉树(AVL树)
- AVL树(平衡二叉树)
- AVL树和平衡二叉树 平衡因子 右旋转LL 左旋转RR LR RL
- 平衡二叉树 之 AVL树
- AVL树(平衡二叉树)
- 平衡二叉树(AVL树)
- 平衡二叉树之AVL树
- 一步一步写平衡二叉树(AVL树)
- 平衡二叉树(avl树)
- java实现AVL树(一种自平衡二叉树)数据结构
- 13.动态查找.平衡二叉树(AVL树)
- 平衡二叉树,AVL树之图解篇
- 平衡二叉树,AVL树之图解篇
- 平衡二叉树(AVL树)
- 一步一步写平衡二叉树(AVL树)
- 平衡二叉树(AVL树)小结