算法——二叉搜索树

二叉搜索树

定义

  1. 首先应该是二叉树;
  2. 其次某节点左子树键值小于该节点键值,其右子树键值大于等于该节点键值。

基本性质

  1. 二叉搜索树的基本操作(search、min、max、insert、delete)和树高成正比;
  2. 随机构造的二叉搜索树,树高期望值为O(log(n)),说明两点:A.无论如何变化,树高在O(log(n))上下变化;B.二叉搜索树可能退化成链表,也就是树高就是节点个数,红黑树就是二叉搜索树的变形,能够确保树高为O(log(n))。

基本操作代码实现

删除

  基本操作中删除比较了,可分为三种情况,上图看就明白了:
二叉搜索树删除示意图
  上图中第三、四行同属一种情况,但四需要先转换成三来处理,即先要将待删除节点的右子树变形为右子树根节点为右子树最小节点。

基本操作代码

import java.util.Random;

public class BinarySearchTree {

    private static class Node {
        public Node left;
        public Node right;
        public int key;
        public Node pre;
    }


    private static int[] getRandomInts(int count, int max) {

        if (count <= 0 || max <= 0) {
            return null;
        }

        Random random = new Random();

        int[] result = new int[count];

        for (int i = 0; i < count; i++) {
            result[i] = random.nextInt(max);
        }

        return result;
    }

    private static Node insertNode(Node root, Node node) {
        Node currentPre = null;
        Node current = root;

        // 找到待插入节点的父节点
        while (current != null) {
            currentPre = current;
            if (current.key < node.key) {
                current = current.left;
            } else {
                current = current.right;
            }
        }

        node.pre = currentPre;
        // 待插入节点为树中第一个节点
        if (currentPre == null) {
            root = node;
            return root;
        } else {
            if (node.key < currentPre.key) {
                currentPre.left = node;
            } else {
                currentPre.right = node;
            }
        }

        return root;
    }

    private static void transplant(Node root, Node u, Node v) {
        if (u.pre == null) {
            root = v;
        } else if (u == u.pre.left) {
            u.pre.left = v;
        } else {
            u.pre.right = v;
        }

        if (v != null) {
            v.pre = u.pre;
        }
    }

    private static Node minimum(Node node) {
        Node currentPre = null;
        Node current = node;
        while (current != null) {
            currentPre = current;
            current = current.left;
        }

        return currentPre;
    }

    private static void delete(Node root, Node z) {
        if (z.left == null) {
            transplant(root, z, z.right);
        } else if (z.right == null) {
            transplant(root, z, z.left);
        } else {
            Node y = minimum(z.right);

            /*
             * 如果待删除节点的右子节点不是右子树中最小的(即待删除节点的右子节点有左子节点),需要将待删除节点的右子树变形:
             * 找到待删除节点右子树中最小的节点y,删除此节点,并将y插入为待删除节点右子树的根节点
             */
            if (y.pre != z) {
                transplant(root, y, y.right);
                y.right = z.right;
                y.right.pre = y;
            }

            /*
             * 统一处理,待删除节点的右子节点为右子树最小节点
             */
            transplant(root, z, y);
            y.left = z.left;
            y.left.pre = y;
        }
    }

    private static Node generateTree(int[] randomInts) {
        if (randomInts == null) {
            return null;
        }
        int length = randomInts.length;
        Node root = null;
        for (int i = 1; i < length; i++) {
            Node node = new Node();
            node.key = randomInts[i];
            root = insertNode(root, node);
        }

        return root;
    }



    public static void main(String[] args) {
        int[] randomInts = getRandomInts(10, 100);
        Node root = generateTree(randomInts);
    }
}

参考文档

《算法导论》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值