【c++】【数据结构】二叉搜索树详解
目录
- 二叉搜索树的定义
- 二叉搜索树的模拟实现
- 查找函数
- 循环版
- 递归版
- 插入函数
- 循环版
- 递归版
- 删除函数
- 循环版
- 递归版
二叉搜索树的定义
二叉搜索树是一种特别的二叉树,是二叉树的搜索特化版。学过排序的都知道,在数组有序的情况下二分查找可以以极高的频率找到指定值,但以数组有序为前提未免太过理想。这时就有人想出了二叉搜索树,二叉搜索树具有以下性质:
1.可以为空树。
2.若左子树不为空,则左子树中所有结点的值都小于根结点的值。
3.若右子树不为空,则右子树中所有结点的值都大于根结点的值。
4.它的左右子树也分别为二叉搜索树。
这样,我们就能通过与根节点比较,小于根节点的值就转移到左子树的根节点,大于就转移到右子树的根节点,通过不断重复此过程的方式就能找到是否有这个数,这样最多只要查找二叉搜索树的高度次,理想情况下就是logN的实际复杂度。这看起来很美好,但是理想很丰满,现实很骨感,
这样一种类似链表的结构也是二叉搜索树,这时它的效率还高吗,跟暴力查找没区别了,虽然这只是一种极端情况,但这也体现出这种普通二叉搜索的问题所在,那就是排不满的话效率会受影响,排的越不满,效率越低,而排的满不满这件事又与根节点以及每个子树的根节点有关,也是一件所随机不可控的事,所以二叉搜索树的查找效率只有N而已,但这个思路无疑是一个好思路,只需要解决结点排不满的问题就能实现logN的效率,后续的AVL树和红黑树就解决了这样的问题,他们也是二叉搜索树。
二叉搜索树的模拟实现
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<string>using namespace std;template<class K, class V>
struct BSTreeNode
{K _key;V _value;BSTreeNode* _left;BSTreeNode* _right;BSTreeNode(K key = K(), V value = V()) :_key(key),_value(value),_left(nullptr),_right(nullptr){}
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:BSTree():_root(nullptr){}BSTree(const BSTree<K, V>& t){copy(_root, t._root);}~BSTree(){Destroy(_root);}BSTree<K, V>& operator=(BSTree<K, V> t){swap(_root, t._root);return *this;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* cur = _root;Node* prev = nullptr;while (cur){if (key < cur->_key){prev = cur;cur = cur->_left;}else if (key > cur->_key){prev = cur;cur = cur->_right;}else{return false;}}Node* newnode = new Node(key, value);if (key > prev->_key)prev->_right = newnode;elseprev->_left = newnode;return true;}bool Find(const K& key){Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->_left;}else if (key > cur->_key){cur = cur->_right;}else{return true;}}return false;}bool Erase(const K& key){Node* cur = _root;Node* prev = nullptr;while (cur){if (key > cur->_key){prev = cur;cur = cur->_right;}else if (key < cur->_key){prev = cur;cur = cur->_left;}else//找到了{if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (prev->_left == cur)prev->_left = cur->_right;elseprev->_right = cur->_right;}}else if (cur->_right == nullptr){if(cur == _root){_root = cur->_right;}else{if (prev->_left == cur)prev->_left = cur->_left;elseprev->_right = cur->_left;}}else{Node* leftmax = cur->_left;Node* leftmax_prev = cur;while (leftmax->_right){leftmax_prev = leftmax;leftmax = leftmax->_right;}swap(leftmax->_key, cur->_key);swap(leftmax->_value, cur->_value);if (leftmax_prev->_left == leftmax)leftmax_prev->_left = leftmax->_left; elseleftmax_prev->_right = leftmax->_left;cur = leftmax;}delete cur;return true;}}return false;}void InOrder()//中序遍历,结果是顺序{_InOrder(_root);}bool InsertR(const K& key, const V& value){return _InsertR(_root, key, value);}bool EraseR(const K& key){return _Erase(_root, key);}bool FindR(const K& key){return _Find(_root, key);}
private:void copy(Node*& root, Node* const& t){if (t == nullptr) return;root = new Node(t->_key, t->_value);copy(root->_left, t->_left);copy(root->_right, t->_right);}void Destroy(Node*& root){if (root == nullptr) return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}bool _Find(Node*& root, const K& key){if (root == nullptr) return false;if (root->_key == key) return true;if (key > root->_key) return _Find(root->_right, key);if (key < root->_key) return _Find(root->_left, key);}bool _Erase(Node*& root, const K& key){if (root == nullptr) return false;if (key > root->_key){_Erase(root->_right, key);}else if (key < root->_key){_Erase(root->_left, key);}else{Node* prev = root;if (root->_left == nullptr) {root = root->_right;}else if (root->_right == nullptr) {root = root->_left;}else{Node* leftmax = root->_left;while (leftmax->_right){leftmax = leftmax->_right;}swap(leftmax->_key, root->_key);swap(leftmax->_value, root->_value);return _Erase(root->_left, key);//leftmax不能传,交换完成之后二叉的位置被破坏,必须传root->_left,不然就往右边找了}delete prev;return true;}}bool _InsertR(Node*& root, const K& key, const V& value){if (root == nullptr) {root = new Node(key, value);return true;}if (key > root->_key){return _InsertR(root->_right, key, value);}else if (key < root->_key){return _InsertR(root->_left, key, value);}else{return false;}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " " << root->_value << endl;_InOrder(root->_right);}Node* _root;
};
首先二叉搜索的结点采用了Key-Value(键值对)模型。Key作为查找的索引,而Value是与其映射的数据,通过这样的方式,可以实现数据的高效管理。其次,由于二叉搜索的结构,一些函数我写出了循环实现与递归实现的版本。
查找函数
循环版
Node* Find(const K& key)
{Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->_left;}else if (key > cur->_key){cur = cur->_right;}else{return cur;}}return nullptr;
}
循环实现的思路非常简单,创建一个指向根节点的指针cur,比较Key,要查找的Key小于当前根节点的就将根节点的左指针赋值给cur,要查找的Key大于当前根节点的就将根节点的右指针赋值给cur,不断被重复直到找到了或者cur指向空,找到返回true,没找到返回false。
递归版
Node* FindR(const K& key){return _Find(_root, key);}
private:Node* _Find(Node*& root, const K& key){if (root == nullptr) return nullptr;if (root->_key == key) return root;if (key > root->_key) return _Find(root->_right, key);if (key < root->_key) return _Find(root->_left, key);}
由于类外无法访问私有变量且为了接口统一,所以这里又封装了一层。递归版的实现也很简单,指针为空就返回false表示没找到,指针是要找的值就返回true,都不是就比较Key向子树转移。
插入函数
循环版
bool Insert(const K& key, const V& value)
{if (_root == nullptr){_root = new Node(key, value);return true;}Node* cur = _root;Node* prev = nullptr;while (cur){if (key < cur->_key){prev = cur;cur = cur->_left;}else if (key > cur->_key){prev = cur;cur = cur->_right;}else{return false;}}Node* newnode = new Node(key, value);if (key > prev->_key)prev->_right = newnode;elseprev->_left = newnode;return true;
}
对于插入函数,我们首先要考虑空树的情况,根结点指针为空的情况就直接创建根节点返回就行了。如果不是空树,创建两个结点指针,因为是要插入,需要知道插入位置的父节点所以要有两个指针。之后只需要像查找函数一样不断比较当前节点的Key与要插入的值,然后向左子树或右子树转移就行,如果遇到了相同的值,就停止插入返回false表示插入失败,因为我们这里实现的是没有相同值的二叉搜索树。如果指针为空了就表示找到空位了,这时根据父结点的值与要插入的值插入左边或者右边就行。
递归版
bool InsertR(const K& key, const V& value){return _InsertR(_root, key, value);}
private:bool _InsertR(Node*& root, const K& key, const V& value){if (root == nullptr) {root = new Node(key, value);return true;}if (key > root->_key){return _InsertR(root->_right, key, value);}else if (key < root->_key){return _InsertR(root->_left, key, value);}else{return false;}}
同样是先对接口封装一层,递归先对终止情况进行判断,如果为空就创建结点赋值给root,注意这里就不需要用两个指针记录父节点,因为这里用的是引用,root就是父节点对应指针(左或者右,原本还要判断的)的引用,修改root也就完成了对于父节点指针的修改,非常巧妙的完成了一个参数两用(循环就不能完成这样的操作,因为c++的引用是不能改变所指向的对象的,所以不能,循环通过不断开辟函数栈帧传值引用实现了多个引用模拟可以改变指向的引用的情况)。如果不为空就比较Key的大小做出对应操作。
删除函数
循环版
bool Erase(const K& key)
{Node* cur = _root;Node* prev = nullptr;while (cur){if (key > cur->_key){prev = cur;cur = cur->_right;}else if (key < cur->_key){prev = cur;cur = cur->_left;}else//找到了{if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (prev->_left == cur)prev->_left = cur->_right;elseprev->_right = cur->_right;}}else if (cur->_right == nullptr){if(cur == _root){_root = cur->_right;}else{if (prev->_left == cur)prev->_left = cur->_left;elseprev->_right = cur->_left;}}else{Node* leftmax = cur->_left;Node* leftmax_prev = cur;while (leftmax->_right){leftmax_prev = leftmax;leftmax = leftmax->_right;}swap(leftmax->_key, cur->_key);swap(leftmax->_value, cur->_value);if (leftmax_prev->_left == leftmax)leftmax_prev->_left = leftmax->_left; elseleftmax_prev->_right = leftmax->_left;cur = leftmax;}delete cur;return true;}}return false;
}
删除函数是实现最为复杂的一个函数,首先是创建两个指针,删除同样需要知道父结点的地址用来改变父结点指向删除位置的指针。再之后就是循环,首先我们先找到要删除的值,所以还是和查找函数一样,先循环查找,找到了再进入下一个问题,怎么删?我们将找到的结点的情况分为四种,没有子结点也就是叶子节点,有一个右节点,有一个左节点,有两个节点。没有子节点的话,直接删除再将对应父节点的指针置空就好了,因为没有子结点的情况的处理方式与只有一个子节点的处理方式一样,都是删除节点然后将父节点的对应指针指向自己的子节点(叶子节点的子节点为空),所以没有写单独的判断,无论是作为只有作为左结点还是只有右节点的情况处理都是可以的;只有左节点的话,注意删除再将父节点的对应指针只想自己的左节点就好了,,要注意要删除的就是根节点自己这种情况,因为根节点没有父节点,所以要特殊判断处理,处理的方式也很简单,就是不必处理父结点的指针,而是将根节点指针指向左节点;只有右节点的话,和只有左节点对应,删除再将父节点的对应指针只想自己的右节点,再将根节点指向右节点就好了;有两个节点的话就会比较麻烦,直接删会多出来左右子树,只有一个还好,可以直接给删除结点的父结点,但是有两个的话就麻烦了,所以这里采取和堆的思路一样,先找一个替换上来,之后删除替换下去的那个。那要找哪个才能保证能维持住原本的结构呢?答案是左子树的最大值和右子树的最小值,左子树的最大值替换上来后比左子树的所有元素都要大,比右子树中的所有数都要小,右子树的最小值也是同理。这里我选择了左子树的最大值。想找到左节点的最大值,之后交换结点的值,然后就要分两种情况讨论,一种是删除位置的父节点的右指针指向自己,一种是删除位置的父节点的左指针指向自己。可能会有人疑问既然是最大值为什么还有位于父节点的左边这种情况,如图所示,
可能会出现要删除的位置的左子树的根节点没有右子树导致自己就是最大的,此时就要特殊处理。面对这两种情况要将对应的父结点的指针指向删除位置的子节点的左指针(因为最大,所以只会有左节点存在的可能,也可能不存在)。
递归版
bool EraseR(const K& key){return _Erase(_root, key);}
private:bool _Erase(Node*& root, const K& key){if (root == nullptr) return false;if (key > root->_key){_Erase(root->_right, key);}else if (key < root->_key){_Erase(root->_left, key);}else{Node* prev = root;if (root->_left == nullptr) {root = root->_right;}else if (root->_right == nullptr) {root = root->_left;}else{Node* leftmax = root->_left;while (leftmax->_right){leftmax = leftmax->_right;}swap(leftmax->_key, root->_key);swap(leftmax->_value, root->_value);return _Erase(root->_left, key);//leftmax不能传,交换完成之后二叉的位置被破坏,必须传root->_left,不然就往右边找了}delete prev;return true;}}
递归的思路大致与循环相同,将查找的过程用循环实现,找到根据对应的节点然后删除,这里同样使用了引用父节点指针达到一个参数两用的做法,所以只需要将对应的指针赋值给root就好了,在有两个子结点交换删除的最后还复用了自己,但要注意参数传根节点的左节点(左子树的根节点),因为传的是根节点会因为交换打乱次序的问题找不到要删的结点,注意此时不要穿局部参数,因为会用到引用的特性,如果传局部参数就无法改变根节点的内部指针了。
剩下的函数较为简单,不过多赘述。
相关文章:
【c++】【数据结构】二叉搜索树详解
目录 二叉搜索树的定义二叉搜索树的模拟实现查找函数循环版递归版 插入函数循环版递归版 删除函数循环版递归版 二叉搜索树的定义 二叉搜索树是一种特别的二叉树,是二叉树的搜索特化版。学过排序的都知道,在数组有序的情况下二分查找可以以极高的频率找…...
高精地图数据错误的侵权责任认定与应对之道
首席数据官高鹏律师团队 在自动驾驶与智慧交通快速发展的今天,高精地图作为核心基础设施,其数据准确性直接关系到公共安全。然而,技术并非完美,一旦因地图数据错误导致事故或损失,比如当自动驾驶汽车因高精地图数据错…...
Python训练营打卡——DAY22(2025.5.11)
复习日 学习参考如何使用kaggle平台,写下使用注意点,并对下述比赛提交代码 泰坦尼克号——来自灾难的机器学习 数据来源: kaggle泰坦里克号人员生还预测 挑战 泰坦尼克号沉没是历史上最臭名昭著的海难之一。 1912年4月15日,在被普…...
【计算机视觉】OpenCV实战项目 :Image_Cartooning_Web_App:基于深度学习的图像卡通化
Image_Cartooning_Web_App:基于深度学习的图像卡通化Web应用深度解析 1. 项目概述2. 技术原理与模型架构2.1 核心算法2.2 系统架构 3. 实战部署指南3.1 环境配置3.2 模型部署3.3 处理流程示例 4. 常见问题与解决方案4.1 模型加载失败4.2 显存溢出4.3 边缘伪影 5. 关…...
王道计算机网络知识点总结
计算机网络知识点总结 一、计算机网络体系结构 (一)计算机网络概述 计算机网络概念:互连的、自治的计算机系统的集合,目的是资源共享,组成包括多台自治计算机,规则是网络协议。 计算机网络的组成&#…...
Java学习笔记(对象)
一、对象本质 状态(State):通过成员变量(Field)描述 行为(Behavior):通过成员方法(Method)实现 class Person {String name;int age;void eat() {System.o…...
并发笔记-给数据上锁(二)
文章目录 核心挑战 (The CRUX)29.1 并发计数器 (Concurrent Counters)1. 简单非并发计数器 (Figure 29.1)2. 同步计数器(单锁版本 - Coarse-Grained Lock, Figure 29.2)3. 可伸缩计数:近似/懒惰计数器 (Approximate/Sloppy Counter, Figure 2…...
Three.js + React 实战系列 - 页脚区域 Footer 组件 ✨
对个人主页设计和实现感兴趣的朋友可以订阅我的专栏哦!!谢谢大家!!! 为个人主页画上完美句号:设计一个美观实用的页脚组件 在完成 Hero、About、Projects、Contact 等模块后,我们为整个页面添上…...
基于Flask、Bootstrap及深度学习的水库智能监测分析平台
基于Flask、Bootstrap及深度学习的水库智能监测分析平台 项目介绍 本项目是基于Flask框架构建的水库智能监测分析平台,集水库数据管理、实时监测预警、可视化分析和智能预测功能于一体。 预测水位的预警级别:蓝色预警没有超过正常水位且接近正常水位1米…...
JavaSE核心知识点02面向对象编程02-08(异常处理)
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 JavaSE核心知识点02面向对象编程02-08&#…...
7系列 之 SelectIO 资源
背景 《ug471_7Series_SelectIO.pdf》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性,并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resource…...
【目标检测系列】YOLOV1解读
目标检测系列文章 目录 目标检测系列文章📄 论文标题🧠 论文逻辑梳理1. 引言部分梳理 (动机与思想) 📝 三句话总结🔍 方法逻辑梳理🚀 关键创新点🔗 方法流程图关键疑问解答Q1: 关于 YOLOv1 中的 "conf…...
GIF图像技术介绍
以下是对GIF格式的详细介绍,涵盖其定义、发展历程、技术特性、应用场景及与其他格式的对比: 一、GIF的定义与起源 GIF(Graphics Interchange Format,图形交换格式)由美国CompuServe公司于1987年推出,旨在解决早期互联网带宽不足的问题。其开发者Steve Wilhite采用LZW无损…...
【TI MSPM0】CCS工程管理
一、关于WORKSPACE 1.导入工程路径 导入工程时,实际是将工程从原路径复制到了Workspace路径下(默认是在C盘user路径下) 2.工程保存备份 关于工程的保存,可以右击文件夹,点击Reveal打开文件夹 将对应的文件夹进行复…...
牛客周赛 Round 92-题解
牛客周赛 Round 92-题解 A-小红的签到题 code #include<iostream> #include<string> using namespace std; string s; int main() {int n;cin >> n;cout << "a_";for (int i 0; i < n - 2; i )cout << b;return 0; }B-小红的模…...
iVX 图形化编程平台:结合 AI 原生开发的革新与实践
一、技术架构:重构 AI 与编程的交互逻辑 1. 信息密度革命:从线性代码到图形化语义单元 传统文本编程存在显著的信息密度瓶颈。以 "按钮点击→条件判断→调用接口→弹窗反馈" 流程为例,Python 实现需定义函数、处理缩进并编写 30 …...
微服务架构中如何保证服务间通讯的安全
在微服务架构中,保证服务间通信的安全至关重要。服务间的通信通常是通过HTTP、gRPC、消息队列等方式实现的,而这些通信链路可能面临多种安全风险。为了应对这些风险,可以采取多种措施来保证通信安全。 常见的服务间通信风险 1.数据泄露:在服务间通信过程中,敏感数据可能会…...
长短期记忆网络(LSTM)深度解析:从理论到实践的全方位指南
一、LSTM基础理论:超越传统RNN的记忆架构 1.1 RNN的长期依赖问题 传统循环神经网络(RNN)在处理长序列时面临的根本挑战是梯度消失/爆炸问题。当序列长度超过10-20个时间步时,RNN难以学习到早期时间步的信息。数学上,这源于反向传播过程中梯度的链式法则: 复制 下载 ∂…...
FramePack AI图片生成视频 v1.1 整合包
今天,我兴奋地要为大家介绍一款革命性的AI工具——FramePack,这是一个让人眼前一亮的图生视频整合包。想象一下,在2025年5月11日的今天,哪怕你的电脑显存仅有6G,你也可以轻松创造艺术! FramePack的神奇之处…...
在 C++中,指针数组与数组指针的区别
1. 指针数组:本质上是一个数组,数组中的每个元素都是一个指针。也就是说,这个数组存储的是多个指针变量,这些指针可以指向不同的对象(比如不同的变量、数组等) 。 2. 数组指针:本质上是一个指针,这个指针指向一个数组。即它指向的是数组的首地址,通过这个指针可以操作…...
Ubuntu 24服务器部署abp vnext应用程序的完整教程
一、服务器配置 1、安装Nginx 2、安装.NetCore SDK 或.NetCore 运行时 以上两步参考 《UbuntuNginxSupervisord部署.net core web应用程序_nginx部署netcore-CSDN博客》 二、abp vnext程序部署 1、程序发布 使用VS进行发布 2、程序上传 使用winSCP工具 3、openiddict…...
Ingrees 控制器与 Ingress 资源的区别
在 Kubernetes 中,单纯的 Ingress 资源定义文件(YAML)本身不会直接创建 Pod。Ingress 的作用是定义路由规则(如将外部流量路由到集群内的服务),而实际处理流量的 Pod 是由 Ingress 控制器(如 Ng…...
动态路由实现原理及前端控制与后端控制的核心差异
在 Web 开发领域,动态路由是构建灵活、高效应用的关键技术之一。它能够根据不同的条件和请求,动态地决定页面的跳转和数据的加载,极大提升用户体验。本文将深入剖析动态路由的实现原理,并详细探讨前端控制和后端控制两种模式的最大…...
stm32 WDG看门狗
目录 stm32 WDG看门狗一、WDG基础知识1)WDG(Watchdog)看门狗简介 二、IWDG独立看门狗1)IWDG键寄存器2)IWDG超时时间 三、WWDG窗口看门狗1)WWDG框图2)WWDG工作特性3)WWDG超时时间4&am…...
MySQL索引详解(下)(SQL性能分析,索引使用)
索引是MySQL性能优化的核心,但如何精准分析查询瓶颈、合理设计索引,是开发者必须掌握的技能。本文结合实战案例,系统讲解SQL性能分析工具链与索引使用技巧,帮助读者构建高性能数据库系统。 一、SQL性能分析:从宏观到微…...
添加文字标签
上节我们学会了如何在地图中标记位置,那么可不可以为地图添加文字注释呢?答案是肯定的,我们依旧以广州塔为例. //添加文字标签和广告牌var label viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(113.3191,23.109,100),label:{text:"广州塔",font:&…...
数据并行基础概念知识
架构分为PS与ring-allreduce;方法主要是zero系列zeroDP123、ZeroR 、Zero-offerload、Zero-Infinite、Zero 相关博客介绍的很清楚,在这里总结一下 图解系列很通透,通俗易懂1 更详细的介绍后面几种方式,提供动图链接2 提供混合精度…...
Linux系列(3)----用户和用户组管理、系统管理
声明: 本文参考 ❤️肝下25万字的《决战Linux到精通》笔记,你的Linux水平将从入门到入魔❤️【建议收藏】_linux笔记 小小明-CSDN博客 不理解的命令需要自己操作一遍 方可理解 不知道怎么租用服务器并链接的看这个文章 如何租用服务器并通过ssh连接…...
【沉浸式求职学习day36】【初识Maven】
沉浸式求职学习 Maven1. Maven项目架构管理工具2.下载安装Maven3.利用Tomcat和Maven进入一个网站 Maven 为什么要学习这个技术? 在Java Web开发中,需要使用大量的jar包,我们手动去导入,这种操作很麻烦,PASS!…...
Nipype 简单使用教程
Nipype 简单使用教程 基础教程**一、Nipype 核心概念与工作流构建****1. 基本组件****2. 工作流构建步骤** **二、常用接口命令速查表****1. FSL 接口****2. FreeSurfer 接口****3. ANTS 接口****4. 数据处理接口** **三、高级特性与最佳实践****1. 条件执行(基于输…...
DA14585墨水屏学习(2)
一、user_svc2_wr_ind_handler函数 void user_svc2_wr_ind_handler(ke_msg_id_t const msgid,struct custs1_val_write_ind const *param,ke_task_id_t const dest_id,ke_task_id_t const src_id) {// sprintf(buf2,"HEX %d :",param->length);arch_printf("…...
【LeetCode Hot100 | 每日刷题】排序数组
912. 排序数组 - 力扣(LeetCode) 题目: 给你一个整数数组 nums,请你将该数组升序排列。 你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。 示例 1&…...
leetcode热题100——day26
21. 合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 AC代码 # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val0, nextNone): # self.val val # …...
Python httpx库终极指南
一、发展历程与技术定位 1.1 历史演进 起源:httpx 由 Encode 团队开发,于 2019 年首次发布,目标是提供一个现代化的 HTTP 客户端,支持同步和异步操作,并兼容 HTTP/1.1 和 HTTP/2。背景: requests 库虽然功…...
#Redis黑马点评#(五)Redisson详解
目录 一 基于Redis的分布式锁优化 二 Redisson 1 实现步骤 2 Redisson可重入锁机制 3 Redisson可重试机制 4 Redisson超时释放机制 5 RedissonMultiLock解决主从一致性 三 Redis优化秒杀 一 基于Redis的分布式锁优化 二 Redisson Redisson是一个在Redis的基础上实现的…...
redis存储结构
一、存储结构 存储转换: string int:字符串长度 ≤ 20 且能转成整数raw:字符串长度 > 44embstr:字符串长度 ≤ 44附加:CPU 缓存中基本单位为 cacheline 64 字节 list quicklist(双向链表)zi…...
wordpress自学笔记 第三节 独立站产品和类目的三种展示方式
wordpress自学笔记 摘自 超详细WordPress搭建独立站商城教程-第三节 独立站产品和类目的三种展示方式,2025 WordPress搭建独立站教程#WordPress建站教程https://www.bilibili.com/video/BV1rwcteuETZ?spm_id_from333.788.videopod.sections&vd_sourcea0af3b…...
Python 自动化脚本开发秘籍:从入门到实战进阶(6/10)
摘要:本文详细介绍了 Python 自动化脚本开发的全流程,从基础的环境搭建到复杂的实战场景应用,再到进阶的代码优化与性能提升。涵盖数据处理、文件操作、网络交互、Web 测试等核心内容,结合实战案例,助力读者从入门到进…...
封装和分用(网络原理)
UDP/TCP协议知识及相关机制 优质好文推荐👆👆 我们如果想要了解封装与分用,先需要了解TCP/IP五层协议~~ 该图的右边就是TCP/IP五层协议~~需要先理解一下各层是什么含义~ 应用层:直接为用户应用程序提供网络服务和通信协议。它定…...
MySQL数据库容灾设计案例与SQL实现
MySQL数据库容灾设计案例与SQL实现 一、主从复制容灾方案 1. 配置主从复制 -- 在主库执行(创建复制账号) CREATE USER repl_user% IDENTIFIED BY SecurePass123!; GRANT REPLICATION SLAVE ON *.* TO repl_user%;-- 查看主库状态(记录File…...
各类有关NBA数据统计数据集大合集
这些数据我已上传大家在CSDN上直接搜索就可以! 一、【2022-2023 NBA球员统计】数据集 关键词: 篮球 描述: 语境 该数据集每场比赛包含2022-2023常规赛NBA球员统计数据。 请注意,由团队更改产生了重复的球员名称。 * [2021-2022 NBA播放器统计]&#…...
【基于 LangChain 的异步天气查询5】多轮对话天气智能助手
目录 项目概述 1. 天气查询功能 2. 多轮对话与聊天 3. 语音输入与输出 4. 历史记录管理 5. 项目结构 6. 核心功能流程 7. 项目特色 🗂️ 项目目录结构 📄 chat_runnable.py 📄 main.py 📄 history_manager.py 📄 weather_runnable.py 📄 tools.py �…...
图片转ICO图标工具
图片转ICO图标 可批量操作 下载地址: 链接:https://pan.quark.cn/s/6312c565ec98 这个工具是一个批量图片转ICO图标的神器,有了它,以后再也不用为ICO格式的转换烦恼!而且这个软件特别小巧,完全不用安装。…...
istio in action之服务网格和istio组件
微服务和服务网格 微服务 微服务将大系统拆解成一个个独立的、小型的服务单元。每个服务可以独立部署、快速迭代,团队可以自主决策,大大降低了变更风险。当然,微服务不是万能药,它需要强大的自动化和DevOps实践作为支撑。而Isti…...
5 从众效应
引言 有一个成语叫做三人成虎,意思是说,有三个人谎报市上有老虎,听者就信以为真。这种人在社会群体中,容易不加分析地接受大多数人认同的观点或行为的心理倾向,被称为从众效应。 从众效应(Bandwagon Effec…...
超市销售管理系统 - 需求分析阶段报告
1. 系统概述 超市销售管理系统是为中小型超市设计的信息化管理解决方案,旨在通过信息化手段实现商品管理、销售处理、库存管理、会员管理等核心业务流程的数字化,提高超市运营效率和服务质量,同时为管理者提供决策支持数据。 2. 业务需求分…...
懒人美食帮SpringBoot订餐系统开发实现
概述 快速构建一个订餐系统,今天,我们将通过”懒人美食帮”这个基于SpringBoot的订餐系统项目,为大家详细解析从用户登录到多角色权限管理的完整实现方案。本教程特别适合想要学习企业级应用开发的初学者。 主要内容 1. 用户系统设计与实现…...
【计算机视觉】基于Python的相机标定项目Camera-Calibration深度解析
基于Python的相机标定项目Camera-Calibration深度解析 1. 项目概述技术核心 2. 技术原理与数学模型2.1 相机模型2.2 畸变模型 3. 实战指南:项目运行与标定流程3.1 环境配置3.2 数据准备3.3 执行步骤3.4 结果验证 4. 常见问题与解决方案4.1 角点检测失败4.2 标定结果…...
彩票假设学习笔记
彩票假设 文章目录 彩票假设一、基本概念1. 核心观点2. 关键要素 二、彩票假设的用途三、训练流程四、意义和局限性1. 意义2. 局限性 五、总结 一、基本概念 彩票假设(Lottery Ticket Hypothesis)是由 Jonathan Frankle 和 Michael Carbin 在 2019 年的…...
《算法导论(第4版)》阅读笔记:p18-p31
《算法导论(第4版)》学习第 11 天,p18-p31 总结,总计 4 页。 一、技术总结 1. Fourier transform(傅里叶变换) In mathematics, the Fourier transform (FT) is an integral transform that takes a function as input then outputs another function…...