二叉查找树和平衡二叉树

定义

根节点的值大于其左子树任意节点的值,小于其右子树任意节点的值。这一规则适用于二叉查找树种的每一个节点。且没有键值相等的节点。

叶节点:也叫叶子节点,没有子节点的节点

删除节点:寻找比删除节点值大的节点集合种最小的一个节点。

一般不物理删除,直接逻辑删除。

对二叉查找树进行中序遍历,即可得到有序的数列。

普通的二叉查找树容易失去平衡,退化成线性的链表。导致查找和插入的复杂度降低至O(N)。

插入:直接作为叶子节点插入

 

平衡二叉树,又称AVL树。

每个节点的左右子树的高度差的绝对值最大为1。

构建平衡二叉树时,当有新节点插入时,都会判断插入后是否平衡,不平衡,就需要调整。

左旋:以某个节点为支点(旋转节点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点(把晋升之后多余的左子节点出让给降级节点的右子节点

右旋:以某个节点为支点(旋转节点),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点(把晋升之后多余的右子节点出让给降级节点的左子节点

旋转的目的,是将节点多的一只,出让节点给节点少的一支。

需要调整的情况有四种:左左、左右、右左、右右。

左左:在原来的平衡二叉树上,在节点的左子树的左子树下,有新节点插入

左右:在原来的平衡二叉树上,在节点的左子树的右子树下,有新节点插入。需要先左旋,使二叉树变成左左,再右旋。

右左:

右右:

平衡二叉树构建的过程,就是节点插入的过程,插入失衡情况就上面4种,算简单了,下面讲下平衡二叉树节点的删除,删除的情况会复杂一点,复杂的原因主要在于删除了节点之后要维系二叉树的平衡,但是删除二叉树节点总结起来就两个判断:①删除的是什么类型的节点?②删除了节点之后是否导致失衡?

  节点的类型有三种:1.叶子节点;2.只有左子树或只有右子树;3.既有左子树又有右子树。

​  针对这三种节点类型,再引入判断②,所以处理思路分别是:

(1)当删除的节点是叶子节点,则将节点删除,然后从父节点开始,判断是否失衡,如果没有失衡,则再判断父节点的父节点是否失衡,直到根节点,此时到根节点还发现没有失衡,则说此时树是平衡的;如果中间过程发现失衡,则判断属于哪种类型的失衡(左左,左右,右左,右右),然后进行调整。

(2)删除的节点只有左子树或只有右子树,这种情况其实就比删除叶子节点的步骤多一步,就是将节点删除,然后把仅有一支的左子树或右子树替代原有结点的位置,后面的步骤就一样了,从父节点开始,判断是否失衡,如果没有失衡,则再判断父节点的父节点是否失衡,直到根节点,如果中间过程发现失衡,则根据失衡的类型进行调整。

(3)删除的节点既有左子树又有右子树,这种情况又比上面这种多一步,就是中序遍历,找到待删除节点的前驱或者后驱都行,然后与待删除节点互换位置,然后把待删除的节点删掉,后面的步骤也是一样,判断是否失衡,然后根据失衡类型进行调整。
 

package com.tree;

import java.util.Stack;

public class BinaryTree {

    public static void main(String[] args) {
        Node root = null;
        for (int i = 10; i > 0; i--) {
            root = insert(root, new Node(i));
        }
        for (int i = 50; i > 40; i--) {
            root = insert(root, new Node(i));
        }
        for (int i = 30; i > 20; i--) {
            root = insert(root, new Node(i));
        }
        list(root);
        listStack(root);
    }

    //s使用递归方式遍历
    public static void list(Node root) {
        if (root != null) {
            list(root.getLeft());
            System.out.print(root.getData());
            System.out.print("\t");
            list(root.getRight());
        }
    }

    //利用栈的后进先出遍历
    public static void listStack(Node p) {
        System.out.println("");
        Stack<Node> stack = new Stack<>();
        while (!stack.isEmpty() || p != null) {
            while (p != null) {
                stack.push(p);
                p = p.getLeft();
            }
            p = stack.pop();
            System.out.print(p.getData() + "\t");
            p = p.getRight();
        }
    }

    //二叉查找树的插入
    public static Node insert(Node root, Node newNode) {
        if (root == null) {
            root = newNode;
            root.setParent(null);
            return root;
        }
        Node tmp = root;
        while (tmp != null) {
            if (newNode.getData() < tmp.getData()) {
                if (tmp.getLeft() == null) {
                    tmp.setLeft(newNode);
                    newNode.setParent(tmp);
                    break;
                } else {
                    tmp = tmp.getLeft();
                    continue;
                }
            }
            if (newNode.getData() > tmp.getData()) {
                if (tmp.getRight() == null) {
                    tmp.setRight(newNode);
                    newNode.setParent(tmp);
                    break;
                } else {
                    tmp = tmp.getRight();
                    continue;
                }
            }
        }
        return root;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值