算法之美:数据结构之二叉树

        平时写业务代码的时候很少写对应的算法,因为很少会在内存中存储大量数据,在需要比较大量数据的查找时,多会依赖的中间件,而中间件底层就应用了很多不同算法,尤其是树结构的查找存储算法,二分查找算法在树里面有大量应用。

二分查找算法

        也称折半查找(Binary Search),它是一种效率较高的查找方法,时间复杂度O(log2n),要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列 ​​​,在数据量大的情况,比线性查找性能高;在数据量少的情况和线性查找差不多

        线性查找和二分查找效果对比:https://www.cs.usfca.edu/~galles/visualization/Search.html

线性查找

 二分查找

 编码实现

public class BinarySearch {
    public static void main(String[] args) {
        // 定义一个有序数组
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        // 要查找的元素
        int target = 7;
        // 调用二分查找算法
        int index = binarySearch(arr, target);
        if (index == -1) {
            System.out.println("查找的元素不存在");
        } else {
            System.out.println("查找的元素下标为:" + index);
        }
    }

    /**
     * 二分查找算法
     *
     * @param arr    有序数组
     * @param target 要查找的元素
     * @return 返回元素在数组中的下标,如果没有找到返回-1
     */
    public static int binarySearch(int[] arr, int target) {
        // 记录开始位置
        int start = 0;
        // 记录结束位置
        int end = arr.length - 1;
        // 记录中间位置
        int mid;
        // 循环查找
        while (start <= end) {
            // 计算中间位置
            mid = (start + end) / 2;
            // 比较中间位置的值
            if (arr[mid] == target) {
                // 找到元素,返回下标
                return mid;
            } else if (arr[mid] < target) {
                // 中间元素小于目标元素,则在右边查找
                start = mid + 1;
            } else {
                // 中间元素大于目标元素,则在左边查找
                end = mid - 1;
            }
        }
        // 没有找到元素
        return -1;
    }
}

二叉树

什么是树

        是一种非线性的数据结构,它具有层次结构,根节点是树的最高层,叶节点是最低层。
树可以分为二叉树、平衡树、红黑树、B树、B+树等。

常见术语
 根节点在非空树中没有前驱结点的结点,被称为根节点(注意,只有一个根节点)
父节点每个节点除了根节点外,都有一个父节点
子节点每个节点都可以有1个或多个子节点
叶节点没有子节点的节点称为叶节点
节点的度结点所拥有子树个数,叶子结点就是度为0的结点
树的度树里的各个节点度的最大值
层数根节点为第一层,往下一次递增。
高度(深度)结点的深度指从根节点自顶向下逐层累加至该结点时的深度,树的深度是树中深度最大的结点的深度。
路径从一个节点到另一个节点的序列称为路径
森林由一组树组成的集合称为森林
 

什么是二叉树?

        树有很多种,但是每一个结点最多只有两个子节点的树,被称作为二叉树。二叉树的子节点又分成左节点与右节点。二叉树遍历过程中,每个结点都被访问了一次,时间复杂度是 O(n)
在树的大家族中,二叉树是特别高频使用的树,利用二叉树特性,变种延伸特别多,完全二叉树、满二叉树、二叉查找树(二叉排序树)、平衡二叉树(AVL树)、B-Tree、B+Tree、红黑树(自平衡的二叉查找树,JDK 1.8后的HashMap的存储结构) ...

二叉树的遍历

        二叉树分成根节点、左子树和右子树, 根据根节点什么时候被访问,把二叉树遍历分成三种方式。

        前序遍历:首先访问根节点,然后先是访问左子树,最后才到右子树

        以上图为例,顺序为:A B D H E I J C F G

        中序遍历:首先访问左子树,然后到根节点,最后才到右子树

        以上图为例,顺序为:D H B I E J A F C G

        后序遍历:首先访问左子树,然后到右子树,最后才到根节点

        以上图为例,顺序为:H D I J E B F G C A

二叉树拓展

满二叉树

        每个节点都有0个或者2个子节点的二叉树,叶节点都在最底层的二叉树,节点的总数=2^n-1(n为层数)外观看上去是完整的一个三角形。如节点总数=2^4-1=15

完全二叉树

        只有最下面两层节点的度可以小于2,并且最下层的叶节点集中在靠左连续的边界,只允许最后一层有空缺结点且空缺在右边,完全二叉树需保证最后一个节点之前的节点都齐全;对任一结点,如果其右子树的深度为j,则其左子树的深度必为j或j+1;如果把G节点删除的话,它就不属于完全二叉树了,因为它的叶子结点已经是不连续了。

两者区别

        满二叉树的叶节点都在最底层;完全二叉树只有最下面两层节点的度可以小于2,且最下层的叶节点集中在靠左的边界。

编码分析

树的遍历分为:

1、深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,且每个节点只访问一次,访问完一颗子树再去访问后面的子树;
1)前序遍历:首先访问根节点,然后先是访问左子树,最后才到右子树;
2)中序遍历:首先访问左子树,然后到根节点,最后才到右子树;
3)后序遍历:首先访问左子树,然后到右子树,最后到根节点;

2、广度优先遍历:从根节点到叶子节点的层次关系,一层层横向遍历各个节点,访问树结构的第 n+1 层前必须先访问完第 n 层

编码 

        深度优先遍历 实现二叉树的插入、前序、中序、后序查找。树的定义本身是递归定义,因此采用递归的方法去实现树的三种遍历,容易理解而且代码很简洁

public class BinaryTree {

    // 根节点
    TreeNode root;

    public void insertNode(int data) {
        root = insert(root, data);
    }

    private TreeNode insert(TreeNode treeNode, int data) {
        //如果是空则插入第一个节点
        if (treeNode == null) {
            return new TreeNode(data);
        }
        //插左边
        if (data < treeNode.data) {
            treeNode.leftChild = insert(treeNode.leftChild, data);
        }
        //插右边
        else if (data > treeNode.data) {
            treeNode.rightChild = insert(treeNode.rightChild, data);
        } else {
            treeNode.data = data;
        }
        return treeNode;
    }


    // 前序遍历
    public void preOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.print(root.data + " ");
        preOrder(root.leftChild);
        preOrder(root.rightChild);
    }

    // 中序遍历
    public void inOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.leftChild);
        System.out.print(root.data + " ");
        inOrder(root.rightChild);
    }

    // 后序遍历
    public void postOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        postOrder(root.leftChild);
        postOrder(root.rightChild);
        System.out.print(root.data + " ");
    }
}

class TreeNode {
    int data;
    //左节点
    TreeNode leftChild;
    //右节点
    TreeNode rightChild;

    TreeNode(int data) {
        this.data = data;
    }
}

测试

 public static void testBinaryTree(){
        BinaryTree btt=new BinaryTree();
        btt.insertNode(93);
        btt.insertNode(33);
        btt.insertNode(51);
        btt.insertNode(21);
        btt.insertNode(102);
        btt.insertNode(42);
        btt.preOrder(btt.root);
        System.out.println();
        btt.inOrder(btt.root);
        System.out.println();
        btt.postOrder(btt.root);
    }

 输出结果

前序:93 33 21 51 42 102 

中序:21 33 42 51 93 102 

后序:21 42 51 33 102 93 

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

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

相关文章

把 Taro 项目作为一个完整分包,Taro项目里分包的样式丢失

现象&#xff1a; 当我们把 Taro 项目作为原生微信小程序一个完整分包时&#xff0c;Taro项目里分包的样式丢失&#xff0c;示意图如下&#xff1a; 原因&#xff1a; 在node_modules/tarojs/plugin-indie/dist/index.js文件里&#xff0c;限制了只有pages目录下会被引入app.w…

C# WPF编程-事件

C# WPF编程-路由事件 路由事件概要路由事件的三种方式 WPF事件WPF最重要的5类事件&#xff1a;生命周期事件 鼠标事件键盘事件多点触控输入原始触控 路由事件概要 路由事件是具有更强传播能力的事件&#xff0c;它们可在元素树中向上冒泡和向下隧道传播&#xff0c;并沿着传播…

稀碎从零算法笔记Day21-LeetCode:单词规律

题型&#xff1a;哈希表、字符串 链接&#xff1a;290. 单词规律 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&am…

uni-app从零开始快速入门

教程介绍 跨端框架uni-app作为新起之秀&#xff0c;在不到两年的时间内&#xff0c;迅速被广大开发者青睐和推崇&#xff0c;得益于它颠覆性的优势“快”&#xff0c;快到可以节省7套代码。本课程由uni-app开发者团队成员亲授&#xff0c;带领大家无障碍快速掌握完整的uni-app…

QT文件读写操作和内容提取

访问IO设备&#xff0c;需要先调用open()来设置正确的OpenMode(例如ReadOnly或ReadWrite) 打开设备后后&#xff0c;使用write() 或putChar() 写入数据到文件和设备&#xff0c;并通过调用read()&#xff0c;readLine() 或readAll() 进行读取&#xff1b;使用完设备后&#xf…

机器学习——决策树剪枝算法

机器学习——决策树剪枝算法 决策树是一种常用的机器学习模型&#xff0c;它能够根据数据特征的不同进行分类或回归。在决策树的构建过程中&#xff0c;剪枝算法是为了防止过拟合&#xff0c;提高模型的泛化能力而提出的重要技术。本篇博客将介绍剪枝处理的概念、预剪枝和后剪…

代码随想录算法训练营第二十四天| 回溯算法理论基础、LeetCode77. 组合

# 回溯算法理论基础 # Backtracking 理论基础视频讲解&#xff1a;带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili #LeetCode 77. Combinations #LeetCode 77. 视频讲解&#xff1a;带你学透回溯算法-组合问题&#xff08;对应力…

力扣爆刷第103天之CodeTop100五连刷1-5

力扣爆刷第103天之CodeTop100五连刷1-5 文章目录 力扣爆刷第103天之CodeTop100五连刷1-5一、3. 无重复字符的最长子串二、206. 反转链表三、146. LRU 缓存四、215. 数组中的第K个最大元素五、25. K 个一组翻转链表 一、3. 无重复字符的最长子串 题目链接&#xff1a;https://l…

Oracle数据库如果出现乱码,需要查看是否时字符集不一致导致乱码,这样解决

1、如果出现乱码&#xff0c;需要查看是否时字符集不一致导致乱码 以修改为ZHS16GBK字符集为例&#xff0c;具体字符集需要sql查询。 Oracle查看字符集 SELECT * FROM NLS_DATABASE_PARAMETERS p where p.PARAMETERNLS_CHARACTERSET; SELECT USERENV(language) FROM DUAL; 1.…

谷歌seo营销服务有哪些服务?

以我们举例&#xff0c;如果你在做B2B外贸建站&#xff0c;这里有全套保姆式托管服务&#xff0c;让你既省心又省力&#xff0c;七天就能搞定网站建设&#xff0c;快速上线&#xff0c;再来就是谷歌白帽SEO&#xff0c;我们这边强调的是纯白帽操作&#xff0c;专注于高质量的原…

Cmake和opencv环境安装

1 Cmake下载及安装 Download CMake 根据需要下载&#xff0c;历史版本下载方法如下 CMake 的版本号中的后缀 "rc1" 和 "rc2" 表示 Release Candidate 1 和 Release Candidate 2&#xff0c;它们都是候选版本&#xff0c;用于测试新功能和修复 bug。通常情…

uni-app里面如何使用图标

目录 一、导入 1.在官方&#xff08;iconfont-阿里巴巴矢量图标库&#xff09;选择自己想要的图标&#xff0c;加入购物车 2. 在点击购物车下载代码 3.解压文件夹 并更改名字 4.将文件夹&#xff08;iconfont&#xff09;整个放到项目中的static中 5.修改iconfont.css文件…

ctfshow-web入门-反序列化

web254 先看题 <?php/* # -*- coding: utf-8 -*- # Author: h1xa # Date: 2020-12-02 17:44:47 # Last Modified by: h1xa # Last Modified time: 2020-12-02 19:29:02 # email: h1xactfer.com # link: https://ctfer.com*/error_reporting(0); highlight_file(__FIL…

系统架构设计-构建系统应用

1. 系统架构目标与设计原则 在设计系统架构时&#xff0c;我们的目标是确保系统具有以下特点&#xff1a; 可靠性&#xff1a;系统能够持续稳定运行&#xff0c;保证业务可用性。可伸缩性&#xff1a;系统能够根据负载变化自动扩展或收缩&#xff0c;以应对不同的流量需求。容…

string类的详细模拟实现

string类的模拟实现 文章目录 string类的模拟实现前言1. 类的框架设计2. 构造函数与析构函数3. 拷贝构造与重载赋值运算符函数4. 运算符重载5. 成员函数6. 迭代器的实现7. 非成员函数8. 单元测试总结 前言 ​ 在现代编程中&#xff0c;字符串处理是每个程序员都会遇到的基本任…

Web核心简介

简介 web&#xff1a;全球广域网&#xff0c;也称万维网(www)&#xff0c;能够通过浏览器访问的网站 JavaWeb&#xff1a;是用Java技术来解决相关web互联网领域的技术栈 JavaWeb技术栈 B/S架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式&#xff0c;它的…

精神暴力的来源与解药

导致人生病的&#xff0c;不仅是病毒或细菌&#xff0c;也有精神暴力。与病毒破坏物理肌体、摧毁生命不同&#xff0c;精神暴力是让人们在过度的自我狂热中燃尽自我、而毁灭自身的。 21世纪以来&#xff0c;精神方面的疾病越来越多&#xff0c;为什么这样呢&#xff1f;大的背景…

【C语言进阶篇】动态内存管理

【C语言进阶篇】动态内存管理 &#x1f308;个人主页&#xff1a;开敲 &#x1f525;所属专栏&#xff1a;C语言 &#x1f33c;文章目录&#x1f33c; 1. 为什么要有动态内存分配 2.动态内存开辟和释放函数 2.1 动态内存释放函数 2.1.1 free函数 2.2 动态内存开辟函数 2.2.1 …

HTML元素语义化补充之css函数(三)

文章目录 CSS中的函数css函数–varcss函数–calccss函数–blurcss函数–gradientlinear-gradient的使用 CSS中的函数 ◼ 在前面我们有使用过很多个CSS函数: 比如rgb/rgba/translate/rotate/scale等; CSS函数通常可以帮助我们更加灵活的来编写样式的值&#xff1b; ◼ 下面有几…

自动驾驶轨迹规划之时空语义走廊(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.摘要 2.系统架构 3.MPDM 4.时空语义走廊 ​4.1 种子生成 4.2 具有语义边界的cube inflation ​4.3 立方体松弛 本文解析了丁文超老师…