数据结构与算法-树-二分搜索树(一)

二分搜索树

今天我们尝试构建一颗二分搜索树,很多同学只有理论,并没有对树有其编码实践。通过一步步的实现一颗二分搜索树,加深对数据结构树的理解。
二分搜索树,又名二分排序树,有人也叫它二分查找树。

特点

二分搜索树是二叉树, 每个节点的值大于所有左子树节点的值;小于所有右子树节点的值。

每一课子树都是二分搜索树。

image-20240316151544333

二分搜索树java实现

定义树中的节点
public class Node<E>{
    public  E data;
    public Node<E> left;
    public Node<E> right;

    public Node(E data) {
        this.data = data;
    }

    public E getData() {
        return data;
    }

    public void setData(E data) {
        this.data = data;
    }

    public Node<E> getLeft() {
        return left;
    }

    public void setLeft(Node<E> left) {
        this.left = left;
    }

    public Node<E> getRight() {
        return right;
    }

    public void setRight(Node<E> right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                ", left=" + left +
                ", right=" + right +
                '}';
    }
}
构建树模型
第一种方式

使用递归的方式插入节点,构建二分搜索树模型

image-20240316171541090

public class BinaryTree<E extends Comparable<E>> {
    private int size; //定义树中的节点数量


    public Node<E> insert(Node<E> root, E data) {
        if (root == null) {
            root = new Node<>(data);
            size++;
            return root;
        }
        if (data.compareTo(root.data) < 0) {
            root.left = insert(root.left, data);
        }
        if (data.compareTo(root.data) > 0) {
            root.right = insert(root.right, data);
        }
        return root;
    }

测试程序

Node<Integer> root = new Node<>(35);

BinaryTree<Integer> bst = new BinaryTree<>();
bst.insert(root, 32);
bst.insert(root, 12);
bst.insert(root, 55);
bst.insert(root, 10);
bst.insert(root, 77);
bst.insert(root, 11);
bst.insert(root, 6);
bst.insert(root, 72);
bst.insert(root, 53);

new TreePrint<Integer>().print(root);

image-20240316171848641

第二种方式

使用循环的方式检查是否存在节点,如果没有节点则添加节点。

image-20240316172742426

public class BinaryTreex<E extends Comparable<E>> {
    private Node<E> root;

    public BinaryTreex(E data) {
        this.root = new Node<>(data);
    }

    public Node<E> getRoot(){
        return this.root;
    }

    public void insert(E data) {
        Node<E> currNode = root;

        while (currNode != null) {
            if (data.compareTo(currNode.data) > 0) {
                if (currNode.right == null) {
                    currNode.right = new Node<>(data);
                    return;
                }
                currNode = currNode.right;
            } else {
                if (currNode.left == null) {
                    currNode.left = new Node<>(data);
                    return;
                }
                currNode = currNode.left;
            }
        }
    }
}

运行结构

image-20240316172900786

附录:图形打印二叉树

参考引用来自:https://blog.csdn.net/m0_37550986/article/details/126013196。稍作修改

我们采用中序方式遍历所有节点,使用层序方式从上到下打印节点。

package com.ffyc.tree.bst;

import java.util.*;

/**
 * 中序图形效果打印
 *
 * @param <E>
 */
public class TreePrint<E> {
    private final List<Node<E>> mid = new ArrayList<>();//记录bst树的节点
    private final Map<Node<E>, Integer> map = new HashMap<>();//记录节点及位置

    private Queue<E> queue = new ArrayDeque<>();
    private Node<E> root;

    public TreePrint() {
    }

    public TreePrint(Node<E> root) {
        this.root = root;
    }

    /**
     * 中序遍历
     *
     * @param root 树的根节点
     */
    public void inOrder(Node<E> root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        mid.add(root);
        inOrder(root.right);
    }

    /**
     * 使用Map记录节点及位置
     *
     * @param root
     */
    public void init(Node<E> root) {
        if (root == null) {
            return;
        }
        inOrder(root);
        for (int i = 0; i < mid.size(); i++) {
            map.put(mid.get(i), i);
        }
    }

    /**
     * 打印同一层的节点,使用|线和值进行拼接打印
     *
     * @param nodes
     */
    void printLevelNodes(List<Node<E>> nodes) {
        StringBuilder VLine = new StringBuilder();
        StringBuilder dataLine = new StringBuilder();
        StringBuilder line = new StringBuilder();
        int lastNodeIndex = 0;
        int lastRightIndex = 0;

        for (Node<E> node : nodes) {
            int x = map.get(node);
            String addEmpty = getEmpty(x - lastNodeIndex);
            lastNodeIndex = x;
            VLine.append(addEmpty).append("|");//竖线拼接
            dataLine.append(addEmpty).append(node.data); //值拼接

            Node<E> left = node.left;
            Node<E> right = node.right;
            String leftLine = null;
            String rightLine = null;

            int leftIndex = -1;
            int rightIndex = -1;
            if (left != null) {
                leftIndex = map.get(left);
                leftLine = getLineToChildren(x - leftIndex);
            }
            if (right != null) {
                rightIndex = map.get(right);
                rightLine = getLineToChildren(rightIndex - x);
            }

            String curLine = (leftLine == null ? "" : leftLine) + "|" + (rightLine == null ? "" : rightLine);
            if (leftLine == null && rightLine == null) curLine = "";
            //线段之间的间隔
            int dif = (leftIndex == -1 ? x : leftIndex) - lastRightIndex;
            String difEmpty = getEmpty(dif);
            line.append(difEmpty).append(curLine);//拼接线段
            lastRightIndex = rightIndex == -1 ? x : rightIndex;
        }
        System.out.println(VLine + "\n" + dataLine + "\n" + line);
    }

    String getEmpty(int x) {
        StringBuilder empty = new StringBuilder();
        for (int i = 0; i < x; i++) {
            empty.append("\t");
        }
        return empty.toString();
    }


    //链接子线段的长度
    String getLineToChildren(int end) {
        StringBuilder line = new StringBuilder();
        if (end == 0) return line.toString();
        for (int i = 0; i < end; i++) {
            line.append("____");
        }
        return line.toString();
    }

    /**
     * 扫描每一行中每一个节点的左右节点
     *
     * @param lineNodes 每一行的节点
     */
    public void topToDownLevelPrint(List<Node<E>> lineNodes) {
        if (lineNodes.isEmpty()) return;

        printLevelNodes(lineNodes);//打印同一层的节点

        List<Node<E>> children = new ArrayList<>();  //记录当前节点下的所有子节点
        //记录当前节点下的所有左右节点
        for (Node<E> currentNode : lineNodes) {
            if (currentNode.left != null) children.add(currentNode.left);
            if (currentNode.right != null) children.add(currentNode.right);
        }
        topToDownLevelPrint(children);//递归打印下一层节点
    }
    
    /**
     *  调用此方法完成二分搜索树打印
     *  @param root : 根节点
     */
    public void print(Node<E> root) {
        init(root);
        topToDownLevelPrint(new ArrayList<Node<E>>() {{
            add(root);
        }});
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464433.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫与数据可视化源码免费领取

引言 作为一名在软件技术领域深耕多年的专业人士&#xff0c;我不仅在软件开发和项目部署方面积累了丰富的实践经验&#xff0c;更以卓越的技术实力获得了&#x1f3c5;30项软件著作权证书的殊荣。这些成就不仅是对我的技术专长的肯定&#xff0c;也是对我的创新精神和专业承诺…

腾讯云2核2G免费服务器申请流程,2024免费服务器入口

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

深度学习 精选笔记(13.2)深度卷积神经网络-AlexNet模型

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

【C++刷题】优选算法——动态规划第一辑

1.状态表示是什么&#xff1f;简答理解是dp表里的值所表示的含义怎么来的&#xff1f;题目要求经验题目要求分析问题的过程中&#xff0c;发现重复子问题 2.状态转移方程dp[i]......细节问题&#xff1a;3.初始化控制填表的时候不越界4.填表顺序控制在填写当前状态的时候&#…

【S5PV210_视频编解码项目】裸机开发:实现按键的外部中断处理

加粗样式本文所作内容&#xff1a; 基于S5PV210芯片实现按键的外部中断处理程序&#xff0c;搭建中断处理流程框架 S5PV210对于中断处理的操作流程 1 外部中断得到触发&#xff1a; 1&#xff09;外部中断在初始化阶段得到使能 2&#xff09;外界达到了外部中断的触发条件 …

手机网络连接性能API接口:查询手机网络连接性能状态

手机在网状态查询服务是一项非常方便的服务&#xff0c;可以帮助我们随时了解一个手机号码的在网状态。不论是查询自己的手机号码&#xff0c;还是查询他人的手机号码&#xff0c;这个服务都可以帮助我们获取准确的信息。今天&#xff0c;我想和大家介绍一个非常好用的手机在网…

运用html相关知识编写导航栏和二级菜单

相关代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

30.HarmonyOS App(JAVA)鸿蒙系统app多线程任务分发器

HarmonyOS App(JAVA)多线程任务分发器 打印时间&#xff0c;记录到编辑框textfield信息显示 同步分发&#xff0c;异步分发&#xff0c;异步延迟分发&#xff0c;分组任务分发&#xff0c;屏蔽任务分发&#xff0c;多次任务分发 参考代码注释 场景介绍 如果应用的业务逻辑比…

【技术类-04】python实现docx表格文字和段落文字的“手动换行符(软回车)”变成“段落标记(硬回车)”

作品展示&#xff1a; 背景需求&#xff1a; 把python实现docx表格文字和段落文字的“手动换行符&#xff08;软回车&#xff09;”变成“段落标记&#xff08;硬回车&#xff09;合并在一起统计数量 【技术类-02】python实现docx段落文字的“手动换行符&#xff08;软回车&a…

Prometheus 轻量化部署和使用

文章目录 说明Prometheus简介Grafana简介prometheus和Grafana的关系环境准备&#xff08;docker&#xff09;docker安装时间时区问题&#xff08;我的代码中&#xff09;dockers镜像加速和服务器时区设置 数据库准备(mysql、redis)mysql配置redis配置 Prometheus、grafana下载和…

4-如何进行细分市场分析-03 竞争者分析

任何一个行业肯定都是有很多竞争者&#xff0c;我们如何判断这些竞争者对我们有什么样的威胁、什么样的机会、什么样的影响&#xff0c;我们需要去分析这些竞争者。 行业竞争格局如何分析&#xff1f; 我们可以从一些基本指标来入手&#xff0c;如市场集中度、行业利润率。 竞…

Win10系统使用IIS服务搭建WebDAV网站结合内网穿透公网访问本地文件

文章目录 推荐1. 安装IIS必要WebDav组件2. 客户端测试3. cpolar内网穿透3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功总结&#xff1a; 推荐 前些天发现了一个巨牛的人工智能…

短剧小程序软件开发首页接口转发到Selectpage

工具&#xff1a;用的是uniapp开发 技术栈&#xff1a;vue、nide..js、云开发 用时&#xff1a;20工作天 软件&#xff1a;Hb、微信开发者工具 <?php namespace app\api\controller; use app\common\controller\Api; /** * 首页接口 */ class Index extends Api { …

算法思想总结:滑动窗口算法

创作不易&#xff0c;感谢三连 一.长度最小的数组 . - 力扣&#xff08;LeetCode&#xff09;长度最小的数组 class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {int lenINT_MAX,nnums.size(),sum0;//len必须要给一个很大的数&#xf…

【LeetCode每日一题】2684. 矩阵中移动的最大次数

文章目录 [2684. 矩阵中移动的最大次数](https://leetcode.cn/problems/maximum-number-of-moves-in-a-grid/)思虑&#xff1a;代码&#xff1a; 2684. 矩阵中移动的最大次数 思虑&#xff1a; 1.将第一列的所有行坐标&#xff0c;用IntStream 来生成一个范围 [0, m) 内的整数…

reloading,一个很实用的Python库!

Python是一门非常流行的编程语言&#xff0c;它的广泛应用和丰富的第三方库使得开发者们能够轻松完成各种任务。reloading是Python中一个强大的库&#xff0c;它能够在程序运行时重新加载修改过的模块&#xff0c;为开发者提供了便利和灵活性。本文将全面介绍reloading库&#…

警惕MKP勒索病毒,您需要知道的预防和恢复方法。

引言&#xff1a; 在网络世界中&#xff0c;.mkp勒索病毒是一股威胁不可小觑的黑暗势力。它以其毒辣的加密手段威胁着我们的数据安全。本文将深入介绍.mkp勒索病毒&#xff0c;揭示如何恢复被其加密的数据文件&#xff0c;并分享一些预防措施&#xff0c;助您在数字世界中安全…

整数和浮点数在内存中存储及题目

一、整数在内存中存储 整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码。三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&#xff0c;⽤1表⽰“负”&#xff0c;⽽数值位最⾼位的⼀位是被当做符号位&#xff0c;剩余的都是数值位 正整数…

使用ChatGPT高效完成简历制作[中篇]-有爱AI实战教程(五)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 导读&#xff1a;在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#xff0c;如果没…

【JS进阶】第一天

参考视频——黑马程序员 JavaScript 进阶 - 第 1 天 学习作用域、变量提升、闭包等语言特征&#xff0c;加深对 JavaScript 的理解&#xff0c;掌握变量赋值、函数声明的简洁语法&#xff0c;降低代码的冗余度。 理解作用域对程序执行的影响能够分析程序执行的作用域范围理解闭…