我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java实现二分查找树及其相关操作

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java实现二分查找树及其相关操作

二分查找树(Binary Search Tree)的基本操作有搜索、求最大值、求最小值、求前驱、求后继、插入及删除。

对二分查找树的进行基本操作所花费的时间与树的高度成比例。例如有n个节点的完全二叉树,对它进行的基本操作的时间复杂度为O(logn)。然而,如果树是一个有n个节点的线性的链,则在这种情况下的时间复杂度为O(n)。

1、什么是二分查找树

二分查找树是一种有组织的二叉树。我们可以通过链接节点表示这样一棵树。每个节点包含键(key),数据(data),左子节点(left),右子节点(right),父节点(parent)这五种属性。

如果一个节点没有父节点或某个子结点,则其对应的属性的值为null。

创建一个Node.java文件,用如下代码表示节点:


public class Node {
    public int key;
    public int data;
    public Node left;
    public Node right;
    public Node parent;
    
    public Node(){}
    
    public Node(int key) {
        this.key = key;
    }
}

创建一个BinarySearchTree.java文件,用如下代码表示二分查找树:


public class BinarySearchTree {
    public Node root;
}

接下来,会逐步补充代码。

对于存储在二分查找树中的键,必须满足下面这个条件(二分查找树特点)

对于二叉树中的任一节点n,如果left是n左子树中的任何一个节点,有left.key <= n.key;如果right是n右子树中的任一节点,则有n.key<=right.key。

如果我们中序遍历二分查找树,能升序打印出所有的键(key)。

可在BinarySearchTree.java文件中加上如下代码实现中序遍历:


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

    public void innerWalk() {
        this.innerWalk(this.root);
        System.out.println();
    }

2、查询二分查找树

2.1、搜索

在二分查找树中搜索键为key的结点,如果找到,则返回该结点,否则,返回null。可利用二分查找树的特性来查找。

可在BinarySearchTree.java文件中加上如下代码实现搜索:


public Node search(int key) {
        Node pointer = this.root;
        while (pointer != null && pointer.key != key) {
            pointer = key < pointer.key ? pointer.left : pointer.right;
        }
        return pointer;
    }

2.2、最小值与最大值

求键最小的节点,可根据二叉树的特点,从根结点开始,遍历跟踪其左子节点,直到最后一个。

可在Node.java文件中加上如下代码实现:


 public Node minimum() {
        Node pointer = this;
        while(pointer.left != null){
            pointer = pointer.left;
        }
        return pointer;
    }

在BinarySearchTree.java文件中加上如下代码:


public Node minimum() {
        return this.root.minimum();
    }

求键最大的节点,可根据二叉树的特点,从根结点开始,遍历跟踪其右子节点,直到最后一个。

可在Node.java文件中加上如下代码实现:


 public Node maximum() {
        Node pointer = this;
        while(pointer.right != null) {
            pointer = pointer.right;
        }
        return pointer;
    }

在BinarySearchTree.java文件中加上如下代码:


public Node minimum() {
        return this.root.maximum();
    }

2.3、前驱与后继

给定一个二分查找树中的节点,有时我们需要发现它在树中所有结点按键升序排序的情况下的直接后继(后面第一个)。

如果树中所有的键是不同的,结点n的直接后继是大于n.key的最小结点。

如果该结点有右节点,则其直接后继是其右子树键最小的那个结点。如果该结点则判断该结点是其父节点的左子节点还是其右子节点。

如果是左子节点,则返回其父节点。如果是右子节点,判断其父节点的其父节点的父节点的左子节点还是右子节点,以此类推。

如果找不到,则返回null。

可在Node.java文件中加上如下实现代码:


public Node successor() {
        Node pointer = this;
        if (pointer.right != null)
            return pointer.right.minimum();
        Node parentPointer = pointer.parent;
        while (parentPointer != null && parentPointer.right == pointer) {
            pointer = parentPointer;
            parentPointer = parentPointer.parent;
        }
        return pointer;
    }

一个节点的直接前继是指树中所有结点按键升序排序的情况下,该节点的前面第一个。求直接前继的与求直接后继是对称的。

可在Node.java文件中加上如下实现代码:


 public Node predecessor() {
        Node pointer = this;
        if (pointer.left != null)
            return pointer.left.maximum();
        Node parentPointer = pointer.parent;
        while (parentPointer != null && parentPointer.left == pointer) {
            pointer = parentPointer;
            parentPointer = parentPointer.parent;
        }
        return pointer;
    }

3、插入与删除

插入与删除会导致二分查找树发生改变,但必须保持其特点。

3.1、插入

在树中找到一个键(key)最接近要插入结点键(key)的结点,且有可以插入的位置,然后插入合适的位置。

可在BinarySearchTree.java文件中加上如下实现代码:


 public void insert(Node node) {
        Node pointer = this.root;
        Node parentPointer = null;
        while (pointer != null) {
            parentPointer = pointer;
            pointer = node.key < pointer.key ? pointer.left : pointer.right;
        }
        node.parent = parentPointer;
        if (parentPointer == null)
            this.root = node;
        else if (node.key < parentPointer.key) {
            parentPointer.left = node;
        } else {
            parentPointer.right = node;
        }
    }

3.2、删除

删除节点后,我门要保持二分查找树的特点。

如果要删除节点没有任何子节点,直接可以删除它,不用做任何处理。

如果要删除节点只有一个左子树,可以用左子树的根节点代替要删除节点,也可以用左子树中键(key)最大的节点来代替要删除节点。

如果要删除结点只有一个右子树,可以用右子树的根节点代替要删除节点,也可以用右子树中键(key)最小的结点来代替要删除结点。

如果要删除结点既有左子树,又有右子树,可以用左子树中键(key)最大的结点代替要删除结点,也可以用右子树中键最小的结点代替要删除结点。

假设要从二分查找树tree中删除节点node,一种删除方法的具体步骤如下:

  • 如果node没有左子节点,然后我们可以用node的右子节node.right点代替node,node.right可能是或可能不是null。
  • 如果node只有左子节点node.left,则我们用node.left代替node。
  • 如果node有左子节点node.left和右子节点node.right。我么要发现node的直接后继s(node右子树中键最小的结点,它没有左子节点),s在node右子树中,然后用s代替node。这里要考虑下面两种情况:

如果s是node的右子节点,可以用s代替node。
否则,用s的右子节点代替s,然后再用s代替node。

由于我们需要在二分查找树中替换子树的方法,可以先写一个替换子树的方法。

可在BinarySearchTree.java文件中加上如下实现代码:



    private void transplant(Node node1, Node node2) {
        if (node1.parent == null) {
            this.root = node2;
        } else if (node1.parent.left == node1) {
            node1.parent.left = node2;
        } else {
            node1.parent.right = node2;
        }

        if (node2 != null)
            node2.parent = node1.parent;
        node1.parent = null;
    }

接下来解释删除节点操作的代码实现。

可在BinarySearchTree.java文件中加上如下实现代码:


 public void delete(Node node) {
        if (node.left == null) {
            this.transplant(node, node.right);
        } else if (node.right == null) {
            this.transplant(node, node.left);
        } else {
            Node successor = node.successor();
            if (successor.parent != node) {
                this.transplant(successor, successor.right);
                successor.right = node.right;
                successor.right.parent = successor;
            }
            this.transplant(node, successor);
            successor.left = node.left;
            successor.left.parent = successor;
        }
    }

4、完整代码

Node.java文件


public class Node {
    public int key;
    public int data;
    public Node left;
    public Node right;
    public Node parent;

    public Node() {
    }

    public Node(int key) {
        this.key = key;
    }

    public Node minimum() {
        Node pointer = this;
        while (pointer.left != null)
            pointer = pointer.left;
        return pointer;
    }

    public Node maximum() {
        Node pointer = this;
        while (pointer.right != null)
            pointer = pointer.right;
        return pointer;
    }

    public Node successor() {
        Node pointer = this;
        if (pointer.right != null)
            return pointer.right.minimum();
        Node parentPointer = pointer.parent;
        while (parentPointer != null && parentPointer.right == pointer) {
            pointer = parentPointer;
            parentPointer = parentPointer.parent;
        }
        return pointer;
    }

    public Node predecessor() {
        Node pointer = this;
        if (pointer.left != null)
            return pointer.left.maximum();
        Node parentPointer = pointer.parent;
        while (parentPointer != null && parentPointer.left == pointer) {
            pointer = parentPointer;
            parentPointer = parentPointer.parent;
        }
        return pointer;
    }
}

BinarySearchTree.java文件


public class BinarySearchTree {
    public Node root;

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

    public void innerWalk() {
        this.innerWalk(this.root);
        System.out.println();
    }

    public Node search(int key) {
        Node pointer = this.root;
        while (pointer != null && pointer.key != key) {
            pointer = key < pointer.key ? pointer.left : pointer.right;
        }
        return pointer;
    }

    public Node minimum() {
        return this.root.minimum();
    }

    public Node maximum() {
        return this.root.maximum();
    }

    public void insert(Node node) {
        Node pointer = this.root;
        Node parentPointer = null;
        while (pointer != null) {
            parentPointer = pointer;
            pointer = node.key < pointer.key ? pointer.left : pointer.right;
        }
        node.parent = parentPointer;
        if (parentPointer == null)
            this.root = node;
        else if (node.key < parentPointer.key) {
            parentPointer.left = node;
        } else {
            parentPointer.right = node;
        }
    }

    
    private void transplant(Node node1, Node node2) {
        if (node1.parent == null) {
            this.root = node2;
        } else if (node1.parent.left == node1) {
            node1.parent.left = node2;
        } else {
            node1.parent.right = node2;
        }

        if (node2 != null)
            node2.parent = node1.parent;
        node1.parent = null;
    }

    public void delete(Node node) {
        if (node.left == null) {
            this.transplant(node, node.right);
        } else if (node.right == null) {
            this.transplant(node, node.left);
        } else {
            Node successor = node.successor();
            if (successor.parent != node) {
                this.transplant(successor, successor.right);
                successor.right = node.right;
                successor.right.parent = successor;
            }
            this.transplant(node, successor);
            successor.left = node.left;
            successor.left.parent = successor;
        }
    }
}

5、演示

演示代码


public class Test01 {
    public static void main(String[] args) {
        Node n1 = new Node(1);
        Node n2 = new Node(2);
        Node n3 = new Node(3);
        Node n4 = new Node(4);
        Node n5 = new Node(5);

        BinarySearchTree bst = new BinarySearchTree();
        bst.insert(n3);
        bst.insert(n4);
        bst.insert(n2);
        bst.insert(n1);
        bst.insert(n5);

        System.out.println("bst.minimum().key: " + bst.minimum().key);
        System.out.println("bst.maximum().key: " + bst.maximum().key);
        System.out.println("n3.successor().key: " + n3.successor().key);
        System.out.println("n3.predecessor().key: " + n3.predecessor().key);
        System.out.println("bst.search(4).key: " + bst.search(4).key);

        System.out.print("tree: ");
        bst.innerWalk();
        System.out.print("delete n3: ");
        bst.delete(n3);
        bst.innerWalk();
        System.out.print("delete n2: ");
        bst.delete(n2);
        bst.innerWalk();
        System.out.print("delete n1: ");
        bst.delete(n1);
        bst.innerWalk();
        System.out.print("delete n4: ");
        bst.delete(n4);
        bst.innerWalk();
        System.out.print("delete n5: ");
        bst.delete(n5);
        bst.innerWalk();
    }
}

结果

bst.minimum().key: 1
bst.maximum().key: 5
n3.successor().key: 4
n3.predecessor().key: 2
bst.search(4).key: 4
tree: 1 2 3 4 5
delete n3: 1 2 4 5
delete n2: 1 4 5
delete n1: 4 5
delete n4: 5
delete n5:

到此这篇关于Java实现二分查找树及其相关操作的文章就介绍到这了,更多相关java二分查找树内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java实现二分查找树及其相关操作

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

纯C++二叉树相关操作实例代码分析

这篇“纯C++二叉树相关操作实例代码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“纯C++二叉树相关操作实例代码分析”文
2023-07-02

Python中如何实现二叉排序树的定义、查找、插入、构造、删除操作

这篇文章将为大家详细讲解有关Python中如何实现二叉排序树的定义、查找、插入、构造、删除操作,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 二叉排序树的定义  二叉排序树 ( B i n a r y
2023-06-15

基于红黑树插入操作原理及java实现的示例分析

这篇文章主要介绍基于红黑树插入操作原理及java实现的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!红黑树是一种二叉平衡查找树,每个结点上有一个存储位来表示结点的颜色,可以是RED或BLACK。红黑树具有以下
2023-05-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录