zoukankan      html  css  js  c++  java
  • AVLTree的Java实现

    package com.learn.tree.demo2;

    /**
    * AVL树又叫做平衡二叉树。 AVL树的前提是二叉树(BST或叫做二叉搜索树)
    * 由于在生成BST树的过程中可能会出现线性树结构。比如插入的顺序是:1,2,3,4,5,6n
    * 二叉搜索树就会退化为链表(线性机构),此时所搜的时间复杂度是O(n)。我们知道理想情况下即每个左子树和右子树的高度相等, 搜索时间复杂度log(N).
    *
    * 现在我们要做的事就是让BST在创建的过程中不要向线性发展。方法就是让其在添加新节点的时候,不断调整树的平衡 状态.
    * 定义:它是一颗空树或它的左右两个树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树
    *
    */
    public class AVLTree<T extends Comparable<T>> {

    private Node<T> root;// 根节点

    public AVLTree() {
    root = null;
    }

    /**
    * 获取树的高度
    *
    * @param tree
    * @return
    */
    private int height(Node<T> tree) {
    if (tree != null)
    return tree.height;
    return 0;
    }

    public int height() {
    return height(root);
    }

    /**
    * 获取较大值
    *
    * @param a
    * @param b
    * @return
    */
    private int max(int a, int b) {
    return a > b ? a : b;
    }

    /**
    * 获得较小值
    *
    * @param a
    * @param b
    * @return
    */
    private T min(T a, T b) {
    return a.compareTo(b) < 0 ? a : b;
    }

    /**
    * 前序遍历
    */
    public void preOrder() {
    preOrder(root);
    }

    private void preOrder(Node<T> node) {
    if (node != null) {
    System.out.print(node.key + " ");
    preOrder(node.left);
    preOrder(node.right);
    }
    }

    /**
    * 中序遍历二叉搜索树 得到从小到大序列
    */
    public void inOrder() {
    inOrder(root);
    }

    private void inOrder(Node<T> node) {
    if (node != null) {
    inOrder(node.left);
    System.out.print(node.key + " ");
    inOrder(node.right);
    }
    }

    /**
    * 后序遍历
    */
    public void postOrder() {
    postOrder(root);
    }

    private void postOrder(Node<T> node) {
    if (node != null) {
    postOrder(node.left);
    postOrder(node.right);
    System.out.print(node.key + " ");
    }
    }

    /**
    * 根据键查找节点
    *
    * @param key
    * @return
    */
    public Node<T> search(T key) {
    return search(root, key);
    }

    private Node<T> search(Node<T> node, T key) {
    if (node == null)
    return node;
    if (key.compareTo(node.key) > 0)
    return search(node.right, key);
    else if (key.compareTo(node.key) < 0)
    return search(node.left, key);
    else
    return node;
    }

    /**
    * 迭代法实现查找节点依据key
    *
    * @param key
    * @return
    */
    public Node<T> iteratvieSearch(T key) {
    return iterativeSearch(root, key);
    }

    private Node<T> iterativeSearch(Node<T> node, T key) {
    while (node != null) {
    if (key.compareTo(node.key) > 0)
    node = node.left;
    else if (key.compareTo(node.key) < 0)
    node = node.right;
    else
    return node;
    }
    return node;
    }

    /**
    * 获取avl树中最小的节点
    *
    * @return
    */
    public T minimum() {
    Node<T> node = mininum(root);
    if (node != null)
    return node.key;
    return null;
    }

    private Node<T> mininum(Node<T> node) {
    if (node == null)
    return null;
    while (node.left != null)
    node = node.left;
    return node;
    }

    /**
    * 获取avl树中最大值
    *
    * @return
    */
    public T maxinum() {
    Node<T> node = maxinum(root);
    if (node != null)
    return node.key;
    return null;
    }

    private Node<T> maxinum(Node<T> node) {
    if (node == null)
    return null;
    while (node.right != null)
    node = node.right;
    return node;
    }

    /**
    * LL:左左对应的情况(左单旋转) LL:LeftLeft,也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,
    * 导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡 返回值:旋转后的根节点
    *
    * @param k2
    * @return
    */
    private Node<T> leftLeftRotation(Node<T> k2) {
    Node<T> k1;
    k1 = k2.left;
    k2.left = k1.right;
    k1.right = k2;
    k2.height = max(height(k2.left), height(k2.right)) + 1;
    k1.height = max(height(k1.left), k2.height) + 1;
    return k1;
    }

    /**
    *
    * RR:RightRight,称为"右右"。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,
    * 导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
    *
    * @return
    */

    private Node<T> rightRightRotation(Node<T> k2) {
    Node<T> k1;
    k1 = k2.right;
    k2.right = k1.left;
    k1.left = k2;
    k1.height = max(height(k1.left), height(k1.right)) + 1;
    k2.height = max(height(k2.right), k1.height) + 1;
    return k1;
    }

    /**
    *
    * LR:LeftRight,也称为"左右"。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点
    * ,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
    *
    * @param k
    * @return
    */
    private Node<T> leftRightRotation(Node<T> k) {
    k.left = rightRightRotation(k.left);
    return leftLeftRotation(k);
    }

    /**
    * RL:RightLeft,称为"右左"。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,
    * 导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
    *
    * @param <T>
    */

    private Node<T> rightLeftRotation(Node<T> k) {
    k.right = leftLeftRotation(k.right);
    return rightRightRotation(k);
    }

    public void insert(T key) {
    root = insert(root, key);
    }

    /**
    * 将节点插入到avl树中,并返回根节点
    *
    * @param tree
    * @param key
    * @return
    */

    private Node<T> insert(Node<T> tree, T key) {
    if (tree == null) {
    // 新建节点
    tree = new Node<T>(key, null, null);
    } else {
    int cmp = key.compareTo(tree.key);
    if (cmp < 0) {
    tree.left = insert(tree.left, key);
    // 插入节点后,若avl树逝去平衡,则进行相应的调节
    if (height(tree.left) - height(tree.right) == 2) {
    if (key.compareTo(tree.left.key) < 0)
    tree = leftLeftRotation(tree);
    else
    tree = leftRightRotation(tree);
    }
    } else if (cmp > 0) {
    // 应该将key插入到tree的右子树的情况
    tree.right = insert(tree.right, key);
    if (height(tree.right) - height(tree.left) == 0) {
    if (key.compareTo(tree.right.key) > 0)
    tree = rightRightRotation(tree);
    else
    tree = rightLeftRotation(tree);
    }
    } else {
    // cmp=0
    throw new RuntimeException("添加失败:不允许添加相同的节点!");
    }

    }
    tree.height = max(height(tree.left), height(tree.right)) + 1;
    return tree;
    }

    public void remove(T key) {
    Node<T> z;
    if ((z = search(root, key)) != null)
    root = remove(root, z);
    }

    private Node<T> remove(Node<T> tree, Node<T> z) {
    // 根为空 或者 没有删除的节点,直接返回null
    if (tree == null || z == null)
    return null;
    int cmp = z.key.compareTo(tree.key);
    if (cmp < 0) {
    tree.left = remove(tree.left, z);
    // 删除节点后,若avl树失去平衡,直接返回null
    if (height(tree.right) - height(tree.left) == 2) {
    Node<T> r = tree.right;
    if (height(r.left) > height(r.right))
    tree = rightLeftRotation(tree);
    else
    tree = rightRightRotation(tree);
    }
    } else if (cmp > 0) {
    // 删除节点在tree右子树中
    tree.right = remove(tree.right, z);
    if (height(tree.left) - height(tree.right) == 2) {
    Node<T> l = tree.left;
    if (height(l.right) > height(l.left))
    tree = leftRightRotation(tree);
    else
    tree = leftLeftRotation(tree);
    }

    } else {// tree是对应要删除的节点
    // tree的左右子树非空
    if (tree.left != null && tree.right != null) {
    if (height(tree.left) > height(tree.right)) {
    Node<T> node = maxinum(tree.left);
    tree.key = node.key;
    tree.left = remove(tree.left, node);
    } else {
    Node<T> min = mininum(tree.left);
    tree.key = min.key;
    tree.right = remove(tree.right, min);
    }
    } else {
    Node<T> tmp = tree;
    tree = (tree.left != null) ? tree.left : tree.right;
    tmp = null;
    }
    }
    return tree;
    }

    public void print() {
    if (root != null)
    print(root, root.key, 0);
    }

    /*
    * 打印"二叉查找树"
    *
    * key -- 节点的键值 direction -- 0,表示该节点是根节点; -1,表示该节点是它的父结点的左孩子;
    * 1,表示该节点是它的父结点的右孩子。
    */
    private void print(Node<T> tree, T key, int direction) {
    if (tree != null) {
    if (direction == 0) // tree是根节点
    System.out.printf("%2d is root ", tree.key, key);
    else // tree是分支节点
    System.out.printf("%2d is %2d's %6s child ", tree.key, key, direction == 1 ? "right" : "left");

    print(tree.left, tree.key, -1);
    print(tree.right, tree.key, 1);
    }
    }
    /*
    * 销毁AVL树
    */
    private void destroy(Node<T> tree) {
    if (tree==null)
    return ;

    if (tree.left != null)
    destroy(tree.left);
    if (tree.right != null)
    destroy(tree.right);

    tree = null;
    }

    public void destroy() {
    destroy(root);
    }
    private class Node<T extends Comparable<T>> {
    private T key;
    private int height;
    private Node<T> left;
    private Node<T> right;

    @SuppressWarnings("unused")
    public Node(T key, Node<T> left, Node<T> right) {
    this.key = key;
    this.left = left;
    this.right = right;
    this.height = 0;
    }

    }

    }

    ---------------------------------------AVLTree测试类

    package com.learn.tree.demo2;

    public class AVLTest {
    private static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
    public static void main(String[] args) {

    int i;
    AVLTree<Integer> tree = new AVLTree<Integer>();

    System.out.printf("== 依次添加: ");
    for(i=0; i<arr.length; i++) {
    System.out.printf("%d ", arr[i]);
    tree.insert(arr[i]);
    }

    System.out.printf(" == 前序遍历: ");
    tree.preOrder();

    System.out.printf(" == 中序遍历: ");
    tree.inOrder();

    System.out.printf(" == 后序遍历: ");
    tree.postOrder();
    System.out.printf(" ");

    System.out.printf("== 高度: %d ", tree.height());
    System.out.printf("== 最小值: %d ", tree.minimum());
    System.out.printf("== 最大值: %d ", tree.maxinum());
    System.out.printf("== 树的详细信息: ");


    tree.print();

    i = 8;
    System.out.printf(" == 删除根节点: %d", i);

    tree.remove(i);
    tree.remove(2);
    System.out.printf(" == 中序遍历: ");
    tree.inOrder();

    System.out.printf(" == 高度: %d", tree.height());
    System.out.printf(" == 中序遍历: ");
    tree.inOrder();
    System.out.printf(" == 树的详细信息: ");
    tree.print();



    }

    }

  • 相关阅读:
    Ubuntu中安装gdal python版本
    python中在计算机视觉中的库及基础用法
    Google earth爬取卫星影像数据并进行标注路网的方法
    事务
    文件的下载,随机验证码(无验证)登录注册
    类的加载器和反射
    等待唤醒机制,UDP通信和TCP通信
    线程池,多线程,线程异步,同步和死锁,Lock接口
    多线程, Thread类,Runnable接口
    转换流,缓冲流
  • 原文地址:https://www.cnblogs.com/caibixiang123/p/8422503.html
Copyright © 2011-2022 走看看