二叉搜索树(二叉排序树)

article/2025/8/25 3:19:33

一.概念

二叉搜索树又称二叉排序树,具有以下性质:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

注意:二叉搜索树中序遍历的结果是有序的
在这里插入图片描述

二、基本操作

1.查找元素

思路:二叉搜索树的左子树永远是比根节点小的,而它的右子树则都是比根节点大的值。当前节点比要找的大就往左走,当前元素比要找的小就往右走

	public Node search(int key) {if(root == null) {return null;}Node cur = root;while (cur != null) {if(cur.val == key) {return cur;}else if(cur.val > key) {cur = cur.left;}else{cur = cur.right;}}return null;}

2.插入元素

如果是空树直接把元素插入root位置就好了
思路:因为是二叉搜索树就不能插入重复的元素了,且每次插入都是插入到叶子节点的位置。定义一个 cur 从root开始,插入的元素比当前位置元素小就往左走,比当前位置元素大就往右走,直到为空,所以就需要再定义一个变量parent 记住 cur 的前面的位置。
最后再判断插入到parent 的左子树还是右子树位置

在这里插入图片描述
代码实现:

	public boolean insert(int key) {Node node = new Node(key);if(root == null) {this.root = node;return true;}Node parent = null;Node cur = root;while (cur != null) {if(cur.val == key) {//有相同的元素直接returnreturn false;}else if(cur.val > key) {parent = cur;cur = cur.left;}else{parent = cur;cur = cur.right;}}if (parent.val > key) {parent.left = node;}else{parent.right = node;}return true;}

3.删除元素

删除元素是一个比较难的点,要考虑到很多种情况

  1. cur.left == null

    1. cur 是 root,则 root = cur.right
    2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
    3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right
  2. cur.right == null

    1. cur 是 root,则 root = cur.left
    2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
    3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left
  3. cur.left != null && cur.right != null
    采用替罪羊的方式删除

    1. 找到要删除节点,右树最左边的节点或者找到左树最右边的节点,替换这个两个节点的val值。
    2. 这样才能保证,删除后左树一定比根节点小,右树一定比根节点大
      在这里插入图片描述
	public boolean remove(int key) {if(this.root == null) {return false;}Node parent = null;Node cur = this.root;while (cur != null) {if(cur.val == key) {removeKey(parent,cur);return true;}else if(cur.val < key) {parent = cur;cur = cur.right;}else{parent = cur;cur = cur.left;}}return false;}public void removeKey(Node parent,Node cur) {if(cur.left == null) {if(cur == this.root) {this.root = this.root.right;}else if(cur == parent.left) {parent.left = cur.right;}else{parent.right = cur.right;}}else if(cur.right == null) {if(this.root == cur) {this.root = this.root.left;}else if(cur == parent.left) {parent.left = cur.left;}else{parent.right = cur.left;}}else{//左右都不为空的情况Node targetParent = cur;Node target = cur.right;while (target.left != null) {targetParent = target;target = target.left;}cur.val = target.val;if(targetParent.left == target) {targetParent.left = target.right;}else{targetParent.right = target.right;}}}

4.性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

最好情况:二叉搜索树为完全二叉树,其平均比较次数为 O(log 2 _2 2n)

在这里插入图片描述

最坏情况:二叉搜索树退化为单支树,其平均比较次数为:O(n)

在这里插入图片描述

所有代码:

public class BinarySearchTree {public static class Node {int val;Node left;Node right;public Node(int val) {this.val = val;}}public Node root = null;/*** 查找某个节点* @param key*/public Node search(int key) {if(root == null) {return null;}Node cur = root;while (cur != null) {if(cur.val == key) {return cur;}else if(cur.val > key) {cur = cur.left;}else{cur = cur.right;}}return null;}/*** 插入元素* @param key* @return*/public boolean insert(int key) {Node node = new Node(key);if(root == null) {this.root = node;return true;}Node parent = null;Node cur = root;while (cur != null) {if(cur.val == key) {//有相同的元素直接returnreturn false;}else if(cur.val > key) {parent = cur;cur = cur.left;}else{parent = cur;cur = cur.right;}}if (parent.val > key) {parent.left = node;}else{parent.right = node;}return true;}/*** 删除元素* @param key*/public boolean remove(int key) {if(this.root == null) {return false;}Node parent = null;Node cur = this.root;while (cur != null) {if(cur.val == key) {removeKey(parent,cur);return true;}else if(cur.val < key) {parent = cur;cur = cur.right;}else{parent = cur;cur = cur.left;}}return false;}public void removeKey(Node parent,Node cur) {if(cur.left == null) {if(cur == this.root) {this.root = this.root.right;}else if(cur == parent.left) {parent.left = cur.right;}else{parent.right = cur.right;}}else if(cur.right == null) {if(this.root == cur) {this.root = this.root.left;}else if(cur == parent.left) {parent.left = cur.left;}else{parent.right = cur.left;}}else{Node targetParent = cur;Node target = cur.right;while (target.left != null) {targetParent = target;target = target.left;}cur.val = target.val;if(targetParent.left == target) {targetParent.left = target.right;}else{targetParent.right = target.right;}}}
}

http://chatgpt.dhexx.cn/article/vbZcs5xj.shtml

相关文章

二叉排序树(二叉查找树、二叉搜索树)(图解+完整代码)

目录 ⚽1.什么是二叉排序树 &#x1f3d0;2.构建二叉排序树 &#x1f3c0;3.二叉排序树的查找操作 &#x1f94e;4.二叉排序树的删除 &#x1f3b1;5.完整代码 ⚽1.什么是二叉排序树 我们直接看它的性质&#xff1a; 若它的左子树不空&#xff0c;则左子树上所有结点的值…

种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林

虽然今天不是植树节&#xff0c;但是我今天想种树。 文章目录 树&#xff0c;什么是树&#xff1f;二叉树定义二叉树的创建二叉树的前中后序遍历前序遍历&#xff1a;中序遍历后序遍历已知前序、中序遍历结果&#xff0c;还原二叉树已知后序、中序遍历结果&#xff0c;还原二叉…

java lrucache_Java LruCache 的使用及原理

概述 LRU (Least Recently Used) 的意思就是近期最少使用算法&#xff0c;它的核心思想就是会优先淘汰那些近期最少使用的缓存对象。 在我们日常开发中&#xff0c;UI 界面进行网络图片加载是很正常的一件事情&#xff0c;但是当界面上的图片过于多的时候&#xff0c;不可能每次…

LruCache和DiskLruCache

前言 Android中的三级缓存主要就是内存缓存和硬盘缓存。 Lru(least recently used)意为最近最少使用算法&#xff0c;核心思想就是当缓存满时&#xff0c;会优先淘汰最近最少使用的缓存对象。 LruCache的使用 在Android中可以直接使用LruCache&#xff0c;算法原理是&#xff1…

Android LruCache 缓存

使用场景 1、场景一&#xff1a;图片缓存利器。 可以规定缓存大小、有效避免OOM、自动移除队尾不用的图片缓存、避免HashMap各种问题。 2、场景二&#xff1a;通信缓存 从服务端需要获取数据&#xff0c;但是当访问的数据比较大&#xff0c;比较多&#xff0c;并且是重复数…

Java——LRUCache

概念 简单来说&#xff0c;由于我们的空间是有限的&#xff0c;所以发明了这个数据结构&#xff0c;当我们的空间不够添加新的元素时&#xff0c;就会删除最近最少使用的元素。 其底层逻辑通过哈希表和链表共同实现。哈希表中存储链表的每一个元素&#xff0c;方便进行元素的…

LruCache缓存

Lru算法&#xff1a; Lru 指的是“Least Recently Used-近期最少使用算法”。 1、那么LruCache到底是什么呢&#xff1f; LruCache 是对限定数量的缓存对象持有强引用的缓存&#xff0c;每一次缓存对象被访问&#xff0c;都会被移动到队列的头部。当有对象要被添加到已经达到数…

LruCache 源码解析

1. 概述 对于 Android 开发者&#xff0c;LruCache 肯定不陌生&#xff0c;几乎所有的图片缓存框架都会用到它来实现内存缓存等&#xff0c;可见 LruCache 在 Android 开发中的重要性。LRU 是 Least Recently Used 的缩写&#xff0c;近期最少使用的意思。当我们进行缓存的时候…

LruCache

LruCache这个类是通过Glide得知的&#xff0c;不过它是自己又基于LRU算法自己写了个LruCache工具类&#xff0c;不过基本原理类似&#xff0c;都是基于LRU算法实现的 1.来源 一般来说&#xff0c;缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比…

Android基础-LruCache原理解析

一、Android中的缓存策略 一般来说&#xff0c;缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比较好理解&#xff0c;那么为什么还要删除缓存呢&#xff1f;这是因为不管是内存缓存还是硬盘缓存&#xff0c;它们的缓存大小都是有限的。当缓存满了…

LRUCache详解

1.概念 LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。 Cache的容量有限&#xff0c;因此当Cache的容量用完后&#xff0c;而又有新的内容需要添加进来时&#xff0c; 就需要挑选并舍弃原有的部分内容&#xff0c;从而腾出…

LRUCache 详解

LRU算法详解 一、什么是 LRU 算法 就是一种缓存淘汰策略。 计算机的缓存容量有限&#xff0c;如果缓存满了就要删除一些内容&#xff0c;给新内容腾位置。但问题是&#xff0c;删除哪些内容呢&#xff1f;我们肯定希望删掉哪些没什么用的缓存&#xff0c;而把有用的数据继续…

LRU Cache

前言 哈喽&#xff0c;各位小伙伴大家好&#xff0c;本章内容为大家介绍计算机当中为了提高数据相互传输时的效率而引进的一种重要设计结构叫做LRU Cache,下面将为大家详细介绍什么是LRU Cache,以及它是如何是实现的&#xff0c;如何提升效率的。 1.什么是LRU Cache? LRU是L…

uniapp日历原生插件

<template><!-- 打卡日历页面 --><view classall><view class"bar"><!-- 上一个月 --><view class"previous" click"handleCalendar(0)"><button class"barbtn">上一月</button><…

微信小程序使用日历插件

一&#xff0c;添加插件 1&#xff0c;在你的小程序关联的微信公众平台打开 设置》第三方服务》添加插件 2&#xff0c;直接AppID&#xff08;wx92c68dae5a8bb046&#xff09;搜索到该插件并申请授权&#xff0c;授权成功即可在小程序使用 二&#xff0c;小程序使用插件 app…

日历组件

日历组件&#xff1a; <template><div class"calendar" click.stop><div class"input-wrap"><inputtype"text"v-if"dateChangeSets":placeholder"placeholder"class"input dateChangeSets middle…

vue-calendar基于vue的日历插件

本文转载于https://www.cnblogs.com/zwhgithub/p/8005414.html vue-calendar-component 基于 vue 2.0 开发的轻量&#xff0c;高性能日历组件占用内存小&#xff0c;性能好&#xff0c;样式好看&#xff0c;可扩展性强原生 js 开发&#xff0c;没引入第三方库 效果 Install …

实用插件(一)日历插件——My97DatePicker

注&#xff1a;My97DatePicker插件仅限pc端使用&#xff0c;若是app项目&#xff0c;建议使用ICalendar或者Mobiscroll。 &#xff08;ICalendar插件在华为手机上存在兼容性问题&#xff0c;日期不能滚动&#xff0c;但使用很简单&#xff1b;Mobiscroll使用起来较为复杂&…

sys-calendar.js带节假日的日历插件

下载地址 sys-calendar.js带节假日的日历插件&#xff0c;代码引用比较多。 dd:

jquery日历插件,可自定义日期内容

效果图&#xff1a; 使用&#xff1a; <link href"static/css/raoCalendar.css" rel"stylesheet" type"text/css"><script src"static/js/jquery.min.js"></script> <script src"static/js/raoCalendar.js…