使用AVL树实现Map

一、数组在裂变扩容时可能会出现环、在数组元素转为链表之后选择尾插法插入节点、数组到链表到AVL到RBT的转换

1、数组在裂变扩容时链表中的节点计算出来的位置可能也会发生变化,在多线程情况下调整节点位置可能会出现环。

2、数组中的数组元素转为链表后插入新节点时应选择采用尾插法,因为头插法在并发时可能会产生(jdk1.7之前出现过这种问题)

3、数组------》链表(数组转为链表是为了充分利用内存空间)------》BST(AVL(缺点是在插入节点时需要大量调整))------》RBT

二、HashMap要实现的方法

1、put(K,V):添加键值对

2、get(K):根据键找对应的键值对

3、remove(K):根据键移除对应的键值对

三、实现一棵树的底层有两种方式

1、数组法

浪费一些空间,找起来比较容易

2、节点法

节省空间、访问没有数组快

五、实现AVL树(节点、AVL)

1、节点:K和V,一对看,Pair(K,V)、height、left、right

2、AVLNode<K,V>:K、V是泛型,泛型就是不确定是什么类型

六、Car c = new Car();这行代码在多线程环境下运行是否会出现问题

(1)线程的三大特性

原子性、可见性、有序性

(2) new Car()时发生了三件事

开辟内存空间、初始化对象、引用指向对象

(3)Car c = new Car();这行代码在多线程环境下运行可能会出现对象未初始化异常

(4)解决方案:sychronized(同步锁)、Asychronized(异步锁)

(5)数据库中违背线程无序性的案例

在使用MyBatis框架时,使用SQL语句对数据库进行查询时查询出来的结果是使用Entity对其进行封装的,如果未创建代理对象,就直接对Entity进行访问,会违背线程无序性,出现错误

七、向AVL树中添加节点之后调整平衡的四种情况

1、情况一:LL型

解决方案:右旋

/*** 将当前节点右旋并返回新的节点* @param node 当前节点* @return 新节点*/private AVLNode<K,V> rightRotate(AVLNode<K,V> node){AVLNode<K,V> X = node.left;AVLNode<K,V> T2 = X.right;node.left = T2;X.right = node;// 更新X节点与node节点的高度X.height = Math.max(getHeight(X.left), getHeight(X.right)) + 1;node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;return X;}

2、情况二:RR型

解决方案:左旋

/*** 将当前节点左旋并返回新的节点* @param node 当前节点* @return 新节点*/private AVLNode<K,V> leftRotate(AVLNode<K,V> node){AVLNode<K,V> X = node.right;AVLNode<K,V> T2 = X.left;node.right = T2;X.left = node;// 更新X节点与node节点的高度X.height = Math.max(getHeight(X.left), getHeight(X.right)) + 1;node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;return X;}

3、情况三:LR型

解决方案:先左旋后右旋

// LR 先左旋后右旋if(bf > 1 && balanceFactor(node.left) <= 0){node.left = leftRotate(node.left);return rightRotate(node);}

4、情况四:RL型

解决方案:先右旋后左旋

if(bf < -1 && balanceFactor(node.right) >= 0){node.right = rightRotate(node.right);return leftRotate(node);}

八、从AVL树中删除节点的四种情况

1、情况一:删除节点的左子树和右子树都不为空

解决方案:用删除节点的右子树的最小节点替换掉删除节点

if(node.left != null && node.right != null){AVLNode<K,V> midNode = midNode(node.right);midNode.right = remove(node.right,midNode.pair.key);size ++;midNode.left = node.left;resultNode = midNode;}

2、情况二:删除节点的左节点为空右节点不为空

解决方案:将删除节点的右节点作为新节点

if(node.left == null && node.right != null){resultNode = node.right;}

3、情况三:删除节点的左节点不为空右节点为空

解决方案:将删除节点的左节点作为新节点

if(node.right == null && node.left != null){resultNode = node.left;}

4、情况四:删除节点的左右节点都不为空

解决方案:将null作为新节点

if(node.left == null && node.right == null){resultNode = null;
}

九、检查电脑上有多少行java源代码

public class StatisticsCodeCount {public static int count;public static void Statistics(File file) throws IOException {// 文件if(file.isFile()){if(file.getName().endsWith(".java")){BufferedReader reader = new BufferedReader(new FileReader(file));String line = null;while((line = reader.readLine()) != null){count++;}reader.close();}return;}// 文件夹File[] files = file.listFiles();if(files != null){for(File file1: files){Statistics(file1);}}}public static void main(String[] args) throws IOException {String path = "D:/";File file = new File(path);Statistics(file);System.out.println(StatisticsCodeCount.count*0.8);}
}

十、使用AVL树实现Map

package com.ffyc.avl;/*** 绑定key-value的对象* @param <K> key* @param <V> value*/
public class Pair<K extends Comparable<K>,V> {public K key;public V val;public Pair() {}public Pair(K key, V val) {this.key = key;this.val = val;}@Overridepublic String toString() {return "Pair{" +"key=" + key +", val=" + val +'}';}
}
package com.ffyc.avl;public class AVLNode <K extends Comparable<K>,V> {public int height;// 与节点不相关的,节点高度public Pair<K,V> pair;// 节点值public AVLNode<K,V> left;public AVLNode<K,V> right;public AVLNode() {}public AVLNode(Pair<K, V> pair) {this.pair = pair;this.height = 1;}public static void main(String[] args) {System.out.println(Math.cbrt(1000));}
}
package com.ffyc.avl;/*** AVL树* @param <K> key* @param <V> value*/
public class AVLTree <K extends Comparable<K>,V> {private int size;// 树中节点数目/*** 获取树中的节点数目* @return*/public int getSize(){return size;}/*** 获取当前节点的高度* @param node 当前节点* @return 高度*/private int getHeight(AVLNode<K,V> node){if(node == null) return 0;return node.height;}/*** 获取当前节点的平衡因子* @param node 当前节点* @return 平衡因子* bf > 1 不平衡 左子 >> 右子* bf < -1 不平衡 右子 << 左子* bf == 0 平衡* bf == 1 当前平衡* bf == -1 当前平衡*/private int balanceFactor(AVLNode<K,V> node){if(node == null) return 0;// 特殊处理return getHeight(node.left) - getHeight(node.right);}/*** 将当前节点右旋并返回新的节点* @param node 当前节点* @return 新节点*/private AVLNode<K,V> rightRotate(AVLNode<K,V> node){AVLNode<K,V> X = node.left;AVLNode<K,V> T2 = X.right;node.left = T2;X.right = node;// 更新X节点与node节点的高度X.height = Math.max(getHeight(X.left), getHeight(X.right)) + 1;node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;return X;}/*** 将当前节点左旋并返回新的节点* @param node 当前节点* @return 新节点*/private AVLNode<K,V> leftRotate(AVLNode<K,V> node){AVLNode<K,V> X = node.right;AVLNode<K,V> T2 = X.left;node.right = T2;X.left = node;// 更新X节点与node节点的高度X.height = Math.max(getHeight(X.left), getHeight(X.right)) + 1;node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;return X;}/*** 在当前节点中插入值为pair的节点* @param node 当前节点* @param pair 节点值 key-value绑定对象* @return 插入新节点后的根节点*/public AVLNode<K,V> insert(AVLNode<K,V> node,Pair<K,V> pair){if(node == null){size++;return new AVLNode<>(pair);}// key相等,做数据更新if(pair.key.compareTo(node.pair.key) == 0){node.pair.val = pair.val;}else if(pair.key.compareTo(node.pair.key) < 0){node.left = insert(node.left, pair);}else{node.right = insert(node.right, pair);}// 更新node的高度node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;// 计算node的平衡因子int bf = balanceFactor(node);// LL 右旋if(bf > 1 && balanceFactor(node.left) >= 0){return  rightRotate(node);}// RR 左旋if(bf < -1 && balanceFactor(node.right) <= 0){return leftRotate(node);}// LR 先左旋后右旋if(bf > 1 && balanceFactor(node.left) <= 0){node.left = leftRotate(node.left);return rightRotate(node);}// RL 先右旋后左旋if(bf < -1 && balanceFactor(node.right) >= 0){node.right = rightRotate(node.right);return leftRotate(node);}return node;}/*** 从当前节点中查询键为key的节点* @param node 当前节点* @param key 键* @return 键为key的节点*/public AVLNode<K,V> find(AVLNode<K,V> node, K key){if(node == null) return null;if(key.compareTo(node.pair.key) == 0){return  node;}else if(key.compareTo(node.pair.key) < 0){return find(node.left, key);}else{return find(node.right, key);}}/*** 获取当前节点的最小节点* @param node 当前节点* @return 最小节点*/private AVLNode<K,V> midNode(AVLNode<K,V> node){if(node == null) return null;while (node.left != null){node = node.left;}return node;}/*** 从当前节点中删除键为key的节点* @param node 当前节点* @param key* @return 新节点*/public AVLNode<K,V> remove(AVLNode<K,V> node, K key){if(node == null) return null;AVLNode<K,V> resultNode = null;if(key.compareTo(node.pair.key) == 0){// key找到了if(node.left == null){resultNode = node.right;}if(node.right == null){resultNode = node.left;}if(node.left != null && node.right != null){AVLNode<K,V> midNode = midNode(node.right);midNode.right = remove(node.right,midNode.pair.key);size ++;midNode.left = node.left;resultNode = midNode;}size --;}if(key.compareTo(node.pair.key) < 0){node.left = remove(node.left, key);resultNode = node;}if(key.compareTo(node.pair.key) > 0){node.right = remove(node.right, key);resultNode = node;}// 更新高度,调整平衡// 更新resultNode的高度if(resultNode != null){resultNode.height = Math.max(getHeight(resultNode.left), getHeight(resultNode.right)) + 1;// 计算node的平衡因子int bf = balanceFactor(resultNode);// LL 右旋if(bf > 1 && balanceFactor(resultNode.left) >= 0){return  rightRotate(resultNode);}// RR 左旋if(bf < -1 && balanceFactor(resultNode.right) <= 0){return leftRotate(resultNode);}// LR 先左旋后右旋if(bf > 1 && balanceFactor(resultNode.left) <= 0){resultNode.left = leftRotate(resultNode.left);return rightRotate(resultNode);}// RL 先右旋后左旋if(bf < -1 && balanceFactor(resultNode.right) >= 0){resultNode.right = rightRotate(resultNode.right);return leftRotate(resultNode);}}return resultNode;}
}
package com.ffyc.avl;public class TestAVL {public static void main(String[] args) {AVLTree<Integer,Integer> tree = new AVLTree<>();AVLNode<Integer,Integer> root = null;root = tree.insert(root, new Pair<>(1,15));root = tree.insert(root, new Pair<>(4,22));root = tree.insert(root, new Pair<>(2,11));root = tree.insert(root, new Pair<>(6,25));root = tree.insert(root, new Pair<>(6,99));System.out.println("树中节点的数量:"+tree.getSize());root = tree.remove(root, 9);System.out.println("树中节点的数量:"+tree.getSize());System.out.println(tree.find(root, 4));}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式 享元模式(Flyweight Pattern)

享元模式 简绍 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它的目的是通过共享技术来有效地支持大量细粒度的对象。享元模式可以极大地减少内存的使用&#xff0c;从而提高程序的性能。它特别适用于需要创建大量相似对象的场景&#…

Cypress安装与启动(开始学习记录)

一 Cypress安装 使用npm安装 1.查看node.js npm的版本&#xff0c;输入 npm --version 和 node --version&#xff0c;node.js没安装的可以去中文网下载最新稳定版安装&#xff0c;npm不建议升级到最新版本&#xff0c;会导致安装Cypress时Error: Cannot find module ansi-st…

深入解析ElasticSearch从基础概念到性能优化指南

一.引言 ElasticSearch是一个分布式的搜索和分析引擎&#xff0c;专为处理大规模的结构化和非结构化数据而设计。它建立在Apache Lucene之上&#xff0c;提供了强大的全文搜索能力、高可用性和实时分析的功能。无论是作为日志分析平台&#xff0c;还是作为数据驱动的应用程序的…

在已安装的openresty上添加安装upstream模块报错的解决以及使用Consul服务发现时定时变更nginx的upstream的shell脚本

一、在已经安装好的openresty环境上添加安装upstream模块报错&#xff1a; 在已经安装好的openresty环境上添加安装upstream模块报错&#xff1a;http upstream check module can not find any check server, make sure you ve added the check 的问题解决。 服务器上已经安装好…

初级前端面试

1.介绍自己 2.介绍一下之前做过的项目以及接触的业务 3.最近学的技术&#xff0c;接触的是哪一块&#xff08;回答了vue3&#xff09; 4.vue3在什么时候调用接口 beforeCreate 在实例初始化之后&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 用…

idea中java及java web项目的常见问题

1、乱码问题&#xff0c;主要有几处地方&#xff0c;需要检查。 ①确保文件编码&#xff0c;其实主要就是在idea启动文件中&#xff0c;增加了 -Dfile.encodingUTF-8的设置 ②编辑器默认编码&#xff0c;都改为UTF-8 ③Tomcat的运行配置&#xff0c;编码也改为UTF-8,同样使用…

@EnableScheduling 和 @Scheduled 实现定时任务的任务延期问题

前言 在复盘 ieg 一面看到定时任务阻塞的问题时&#xff0c;研究了下 EnableScheduling 的源码&#xff0c;觉得可以单开一篇文章讲一讲 本文主要讲述了使用 EnableScheduling 可能出现的线程阻塞导致定时任务延期的问题&#xff0c;也顺便解释了动态定时任务源码上的实现 引…

SpringBoot3核心特性-核心原理

目录 传送门前言一、事件和监听器1、生命周期监听2、事件触发时机 二、自动配置原理1、入门理解1.1、自动配置流程1.2、SPI机制1.3、功能开关 2、进阶理解2.1、 SpringBootApplication2.2、 完整启动加载流程 三、自定义starter1、业务代码2、基本抽取3、使用EnableXxx机制4、完…

zynq的PS端mac与RTL8211F的连接要点

目录 1 VCCO_MIO12 PS_MIO_VREF3 PS的引脚4 RXDLY TXDLY5 ZYNQ的MAC可以调整延时吗 1 VCCO_MIO1 接1.8V 2 PS_MIO_VREF 接0.9V&#xff0c;可通过电阻分压 可通过电阻分压 3 PS的引脚 4 RXDLY TXDLY RXDLY RXD[0] TXDLY RXD[1] 与XC7Z020的PS端MAC连接&#xff0c;必须…

计算器软件设计与实现

[实验目的] 1. 掌握软件开发的基本流程 2. 掌握常用的软件开发方式和工具。 [实验内容] 1. 设计一个包含登录界面的计算器软件&#xff0c;该软件可以实现第一次作业中的全部功能&#xff0c;同时可 以保存用户的历史计算记录&#xff08;保存数据最好使用数据库&#xff09;…

CVE-2024-2389 未经身份验证的命令注入

什么是 Progress Flowmon? Progress Flowmon 是一种网络监控和分析工具,可提供对网络流量、性能和安全性的全面洞察。Flowmon 将 Nette PHP 框架用于其 Web 应用程序。 未经身份验证的路由 我们开始在“AllowedModulesDecider.php”文件中枚举未经身份验证的端点,这是一个描…

1.pytest基础知识(默认的测试用例的规则以及基础应用)

一、pytest单元测试框架 1&#xff09;什么是单元测试框架 单元测试是指再软件开发当中&#xff0c;针对软件的最小单位&#xff08;函数&#xff0c;方法&#xff09;进行正确性的检查测试。 2&#xff09;单元测试框架 java&#xff1a;junit和testing python&#xff1a;un…

arcgisPro地理配准

1、添加图像 2、在【影像】选项卡中&#xff0c;点击【地理配准】 3、 点击添加控制点 4、选择影像左上角格点&#xff0c;然后右击填入目标点的投影坐标 5、依次输入四个格角点的坐标 6、点击【变换】按钮&#xff0c;选择【一阶多项式&#xff08;仿射&#xff09;】变换 7…

三种springboot启动时加载方式

三种springboot启动时加载方式一个注解&#xff0c;两个接口&#xff0c;常用于数据预热&#xff1a;PostConstructimplements CommandLineRunnerimplements ApplicationRunnerSlf4j EnableAsync SpringBootApplication public class ApiApplication extends SpringBootServlet…

基于SpringBoot+定时任务实现地图上绘制车辆实时运动轨迹图

目录 1. 项目结构 2. Maven依赖配置 (pom.xml) 3. 实现后端服务 4. 配置文件 (application.properties) 5. 启动项目 6. 访问页面 实现基于北斗卫星的车辆定位和轨迹图的Maven工程&#xff08;使用模拟数据&#xff09;&#xff0c;我们将使用以下技术&#xff1a; Spri…

Scrapy爬虫框架 Spider Middleware 爬虫页中间件

在当今的互联网时代,数据的收集和分析变得越来越重要,爬虫技术作为数据获取的重要手段,受到广泛关注。Scrapy 是一个广受欢迎的 Python 爬虫框架,它以其高效、灵活和易于扩展的特点,成为了开发者的首选工具之一。Scrapy 框架中的中间件(Spider Middlewares)是扩展和定制…

基于Jeecg-boot开发系统--后端篇

背景 Jeecg-boot是一个后台管理系统&#xff0c;其提供能很多基础的功能&#xff0c;我希望在不修改jeecg-boot代码的前提下增加自己的功能。经过几天的折腾终于搞定了。 首先是基于jeecg-boot微服务的方式来扩展的&#xff0c;jeecg-boot微服务本身的搭建过程就不讲了&#x…

【面向对象】设计模式分类

java中设计模式共23种&#xff0c;根据使用场景可分为创建型模式、结构型模式、行为型模式。 创建型&#xff1a; 如何创建对象。 单例模式&#xff1a;保证一个类在一个程序中只能创建一个对象。例如windows任务管理器窗口只需要创建一个。单例模式只创建一个对象&#xff0…

使用c#制作一个小型桌面程序

封装dll 首先使用visual stdio 创建Dll新项目,然后属性管理器导入自己的工程属性表&#xff08;如果没有可以参考visual stdio 如何配置opencv等其他环境&#xff09; 创建完成后 系统会自动生成一些文件&#xff0c;其中 pch.cpp 先不要修改&#xff0c;pch.h中先导入自己需…

GitHub上克隆项目

从GitHub上克隆项目是一个简单且直接的过程&#xff0c;它允许你将远程仓库中的项目复制到你的本地计算机上&#xff0c;以便进行进一步的开发、测试或学习。以下是一个详细的步骤指南&#xff0c;帮助你从GitHub上克隆项目。 一、准备工作 1. 安装Git 在克隆GitHub项目之前…