C++ 二叉树进阶:二叉搜索树

目录

二叉搜索树的概念

二叉搜索树的实现

基本结构

插入

1,当树是空树的时候

2,当树不为空的时候

3,纠正后的代码

查找

删除

1,左为空或右为空

 2,左右都不为空

3,删除的完整代码:

二叉搜索树的完整代码

BSTree.h

test.cpp

二叉搜索树的应用

Key 模型

Key-Value 模型

改造二叉搜索树为KV结构

BSTree.h

test.cpp

二叉搜索树的性能分析


二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为二叉搜索树

注意:二叉搜索树key值不能相同。

二叉搜索树中序遍历是有序的,因为二叉搜索树的定义决定了左子树节点值小于根节点值、右子树节点值大于等于根节点值(每一颗子树也满足),而中序遍历先左子树、再根节点、后右子树的方式使得遍历结果自然有序。 


二叉搜索树的实现

基本结构

二叉搜索树中的每个节点包含两个指针,分别指向左子树和右子树,以及一个存储关键值(key 值)的数据域。这种结构使得二叉搜索树能够以二叉树的形式组织数据,并通过比较节点的关键值来进行高效的查找、插入和删除操作。

二叉搜索树不能修改里面的key值,如果修改了就会破坏二叉搜索树的结构。

//节点的定义
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;   //左节点BSTreeNode<K>* _right;  //右节点K _key;      //存储 key 值BSTreeNode(const K& key)  //构造函数完成初始化:_left(nullptr),_right(nullptr),_key(key){}
};template <class K>  //key 关键字,进行比较
class BSTree  //Binary Search Tree
{typedef BSTreeNode<K> Node;
private:Node* _root = nullptr;  //在类内进行成员初始化
};

插入

1,当树是空树的时候

直接定义一个节点把该节点给 _root。

2,当树不为空的时候

不是空树,去找这个需要插入的位置,插入一定是找一个空的位置,不可能替代某个位置。

如果插入时是相同的元素,则插入失败,因为二叉搜索树不允许出现相同的 key 值。

#pragma once
//节点的定义
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;   //左节点BSTreeNode<K>* _right;  //右节点K _key;      //存储 key 值BSTreeNode(const K& key)  //构造函数完成初始化:_left(nullptr),_right(nullptr),_key(key){}
};template <class K>  //key 关键字,进行比较
class BSTree  //Binary Search Tree
{typedef BSTreeNode<K> Node;
public:bool Insert(const K& key){//1,根为空的时候if (_root == nullptr){_root = new Node(key);}//2,根不为空的时候Node* cur = _root;while (cur){if (key > cur->_key)   //插入的key比当前节点大就往右边走{cur = cur->_right;   }else if (key < cur->_key) //插入的key比当前节点小就往左边走{cur = cur->_left;}else                     {return false; //插入的key和当前节点相等,就插入失败}}cur = new Node(key);return true;}//中序遍历void _InOrder(Node* root) {if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void InOrder() {_InOrder(_root);cout << endl;}
private:Node* _root = nullptr;  //在类内进行成员初始化
};
void Test() 
{BSTree<int> t;int a[] = { 5,3,4,1,7,8,2,6,0,9 };for (auto e : a){t.Insert(e);}t.InOrder();  
}

通过测试我们会发现,这里只有 5 插入成功了,也就是根节点插入成功,那么这段代码存在一定的问题,如何解决呢???

问题:在循环中,只是不断地更新 cur 指针,让它指向树中的不同节点,但没有记录下新节点应该连接的父节点。
    当找到空位置并创建新节点 cur = new Node(key) 后,新节点与树中的其他节点没有任何连接,导致新节点成为一个孤立的节点,没有真正插入到树中。

改进:

  1. 添加一个 parent 指针来记录新节点的父节点。在循环中,当更新 cur 指针时,也同时更新 parent 指针。
  2. 在找到插入位置后,根据 keyparent->_key 的大小关系,将新节点连接到父节点的左子树或右子树。

3,纠正后的代码

#pragma once
//节点的定义
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;   //左节点BSTreeNode<K>* _right;  //右节点K _key;      //存储 key 值BSTreeNode(const K& key)  //构造函数完成初始化:_left(nullptr),_right(nullptr),_key(key){}
};template <class K>  //key 关键字,进行比较
class BSTree  //Binary Search Tree
{typedef BSTreeNode<K> Node;
public:bool Insert(const K& key){//当树是空树的时候if (_root == nullptr) {_root = new Node(key);return true;}//树不为空的时候Node* parent = nullptr;  //用一个节点来记录cur的父亲Node* cur = _root;while (cur){if (key > cur->_key) {parent = cur;   cur = cur->_right;	}else if (key < cur->_key) {parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);if (key > parent->_key)  //判断到底是属于父亲的左树还是右树parent->_right = cur;elseparent->_left = cur;return true;}//中序遍历void _InOrder(Node* root) {if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void InOrder() {_InOrder(_root);cout << endl;}
private:Node* _root = nullptr;  //在类内进行成员初始化
};
void Test() 
{BSTree<int> t;int a[] = { 5,3,4,1,7,8,2,6,0,9 };for (auto e : a){t.Insert(e);}t.InOrder();  
}

查找

查找和插入类似,如果比当前节点小就往左边找,如何比当前节点大就往右边找,不断更新cur,直到找返回 true,如果没有找到,返回 false。

	//查找bool Find(const K& key) {Node* cur = _root;while (cur){if (key > cur->_key) {cur = cur->_right;}else if (key < cur->_key) {cur = cur->_left;}else {return true;}}return false;}

删除

二叉搜索树重点在于删除操作,也比较简单。

在实现Erase的时候我们不能使用Find,因为我们还需用到它的父亲,所以这里还是使用双指针。

当我们试删除这些节点,我们可以发现可以存在这些情况:

1,删除2最好删,把2删除之后,还需要把2的右置成nullpt,不然就是野指针了。

2,  当前节点左为空,父亲指向我的右,当前节点右为空,父亲指向我的左边。

3,叶子结点也可以归类到这种左为空或者右为空,让父亲指向左/右。

3,当左右都不为空的时候不能直接删除,用替换法删除
可以找左子树的最大节点(最右节点)或者右子树的最小节点最左节点)替代它

综上所述:

① 左为空

② 右为空

③ 左右都不为空

1,左为空或右为空

我们不能单单只看cur的左右是否为空,然后直接用parent去指向cur的左右,而是我们需要去观察 cur 属于parent 左边还是右边,如果在左边就用 parent 的左边去指向cur的左或者右,如果在右边就用 parent 的右边去指向cur的左或者右。

右为空和左为空同理。

bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//找到了//1,左边为空if (cur->_left == nullptr){if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;delete cur;}//2,右边为空else if (cur->_right == nullptr) {if (parent->_left = cur)parent->_left = cur->_left;elseparent->_right = cur->_left;delete cur;}else  //3,左右都不为空{}return true;}}return false;}

 2,左右都不为空

左右都不为空:找左树的最大节点,或者右树的最小节点,也就是左子树的最右节点,或者右子树的最左节点

bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//找到了//1,左边为空if (cur->_left == nullptr){if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;delete cur;}//2,右边为空else if (cur->_right == nullptr) {if (parent->_left = cur)parent->_left = cur->_left;elseparent->_right = cur->_left;delete cur;}else  //3,左右都不为空{Node* rightMinParent = nullptr;Node* rightMin = cur->_right;while (rightMin->_left) {rightMinParent = rightMin;rightMin = rightMin->_left;}//替代cur->_key = rightMin->_key;//转换成删除rightMin rightMinParent->_left = rightMin->_right;delete rightMin;}return true;}}return false;}

假设我一上来就删除 7 这棵树存在问题

纠正后的代码:

Node* rightMinParent = cur;
Node* rightMin = cur->_right;
while (rightMin->_left) 
{rightMinParent = rightMin;rightMin = rightMin->_left;
}
//替代
cur->_key = rightMin->_key;
//转换成删除rightMin (rightMin是左为空,父亲指向它的右边)
if (rightMin == rightMinParent->_left) rightMinParent->_left = rightMin->_right;
elserightMinParent->_right = rightMin->_right;
delete rightMin;

如果把这棵树删空也会存在问题 

纠正后的代码: 

if (cur->_left == nullptr)
{if (cur == _root)  //当删除的是根节点的时候{_root = cur->_right;}else {if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;
}
else if (cur->_right == nullptr) 
{if (cur == _root)   //当删除的是根节点的时候{_root = cur->_left;  }else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;
}

3,删除的完整代码:

//删除
bool Erase(const K& key) 
{Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key) {parent = cur;cur = cur->_right;}else if (key < cur->_key) {parent = cur;cur = cur->_left;}else {//找到了,开始删除// 1、左为空// 2、右为空// 3、左右都不为空if (cur->_left == nullptr) {if (cur == _root) {_root = cur->_right;}else {if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr) {if (cur == _root){_root = cur->_left;}else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}else {Node* rightMinParent = cur;Node* rightMin = cur->_right;while (rightMin->_left) {rightMinParent = rightMin;rightMin = rightMin->_left;}//替代cur->_key = rightMin->_key;//转换成删除rightMin (rightMin是左为空,父亲指向它的右边)if (rightMin == rightMinParent->_left) rightMinParent->_left = rightMin->_right;else rightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;
}

二叉搜索树的完整代码

BSTree.h

#pragma once
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key) :_left(nullptr),_right(nullptr),_key(key){}
};template <class K>  //key 关键字,进行比较
class BSTree  //Binary Search Tree
{typedef BSTreeNode<K> Node;
public://插入bool Insert(const K& key) {//当树是空树的时候if (_root == nullptr) {_root = new Node(key);return true;}//树不为空的时候Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key) {parent = cur;cur = cur->_right;	}else if (key < cur->_key) {parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);if (key > parent->_key)parent->_right = cur;elseparent->_left = cur;return true;}//查找bool Find(const K& key) {Node* cur = _root;while (cur){if (key > cur->_key) {cur = cur->_right;}else if (key < cur->_key) {cur = cur->_left;}else {return true;}}return false;}//删除bool Erase(const K& key) {Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key) {parent = cur;cur = cur->_right;}else if (key < cur->_key) {parent = cur;cur = cur->_left;}else {//找到了,开始删除// 1、左为空// 2、右为空// 3、左右都不为空if (cur->_left == nullptr) {if (cur == _root) {_root = cur->_right;}else {if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr) {if (cur == _root){_root = cur->_left;}else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}else {Node* rightMinParent = cur;Node* rightMin = cur->_right;while (rightMin->_left) {rightMinParent = rightMin;rightMin = rightMin->_left;}//替代cur->_key = rightMin->_key;//转换成删除rightMin (rightMin是左为空,父亲指向它的右边)if (rightMin == rightMinParent->_left) rightMinParent->_left = rightMin->_right;else rightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;}//中序遍历void _InOrder(Node* root) {if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void InOrder() {_InOrder(_root);cout << endl;}
private:Node* _root = nullptr;
};void TestBSTree() 
{BSTree<int> t;int a[] = { 5,3,4,1,7,8,2,6,0,9 };for (auto e : a) {t.Insert(e);}t.InOrder();//1.上来我就删除7,有问题t.Erase(7);t.InOrder();t.Erase(8);t.InOrder();//2.把这棵树删空,也会存在问题/*for (auto e : a) {t.Erase(e);}t.InOrder();*/叶子t.Erase(2);t.InOrder();左为空或者右为空t.Erase(8);t.Erase(1);t.InOrder();左右都不为空t.Erase(5);t.InOrder();
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include<string>
#include "BSTree.h"
int main()
{TestBSTree();return 0;
}

二叉搜索树的应用

Key 模型

  • 在 Key 模型中,数据主要围绕一个关键标识符(Key)来组织。通常这个 Key 是一个唯一的标识,用于快速检索数据。例如,在一个简单的学生信息系统中,学生的学号可以作为 Key。系统可以根据学号快速查找对应的学生信息,但是可能存储的信息相对比较单一,主要就是和这个 Key 直接相关的内容。
  • 它类似于一个索引,重点在于通过这个唯一的标识来定位某个特定的数据项。
  • 以上二叉搜索树的实现使用的就是key模型

Key-Value 模型

  • Key - Value 模型则是由一个 Key 和一个与之对应的 Value 组成的键值对。Key 仍然用于检索,但是 Value 可以是各种各样的数据结构,如字符串、数字、对象、数组等。比如在一个缓存系统中,Key 可以是一个 URL,Value 则是这个 URL 对应的网页内容。
  • 这种模型更强调数据的关联性,Key 和 Value 共同构成了一个完整的数据单元,Value 的内容可以非常丰富,并且 Key 和 Value 之间存在一种明确的对应关系。
  • Key 通常是设计为唯一的标识符,用于精确地定位和区分不同的键值对。而 Value 可以是相同的。例如,在一个记录用户购物偏好的系统中,Key 可以是用户的唯一标识(如用户 ID),Value 是用户喜欢的商品类别。多个用户(不同的 Key)可能都喜欢相同的商品类别(相同的 Value)。
  • 实际中 Key-Value模型应用广泛。

改造二叉搜索树为KV结构

BSTree.h
#pragma once
// Key-Value 模型
template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}
};template <class K, class V>  //key 关键字,进行比较
class BSTree  //Binary Search Tree
{typedef BSTreeNode<K, V> Node;
public://插入bool Insert(const K& key, const V& value){//当树是空树的时候if (_root == nullptr){_root = new Node(key, value);return true;}//树不为空的时候Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key, value);if (key > parent->_key)parent->_right = cur;elseparent->_left = cur;return true;}//查找Node* Find(const K& key){Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return cur;}}return nullptr;}//删除bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//找到了,开始删除// 1、左为空// 2、右为空// 3、左右都不为空if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (parent->_right == cur)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}else{Node* rightMinParent = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}//替代cur->_key = rightMin->_key;//转换成删除rightMin (rightMin是左为空,父亲指向它的右边)if (rightMin == rightMinParent->_left)rightMinParent->_left = rightMin->_right;elserightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;}//中序遍历void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);cout << endl;}
private:Node* _root = nullptr;
};void TestBSTree()
{//输入单词,查找单词对应的中文翻译/*BSTree<string, string> dict;dict.Insert("sort", "排序");dict.Insert("string", "字符串");dict.Insert("tree", "树");dict.Insert("insert", "插入");string str;while (cin >> str){BSTreeNode<string, string>* ret = dict.Find(str);if (ret){cout << ret->_value << endl;}else{cout << "无此单词" << endl;}}*///以后很常用,统计水果的个数string strArr[] = { "西瓜","西瓜" ,"樱桃","苹果","香蕉","西瓜" ,"西瓜","哈密瓜" ,"西瓜" ,"西瓜" };BSTree<string, int> countTree;for (auto str : strArr){BSTreeNode<string, int>* ret = countTree.Find(str);if (ret == nullptr){countTree.Insert(str, 1);}else{ret->_value++;}}countTree.InOrder();
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include<string>
#include "BSTree.h"
int main()
{TestBSTree();return 0;
}

二叉搜索树的性能分析

最好情况

  • 对于平衡的二叉搜索树,插入操作首先需要找到插入位置。因为树是平衡的,这个查找过程类似于查找操作,时间复杂度为 O(logN)。
  • 找到位置后,插入新节点的操作本身时间复杂度为O(1) (只需要修改指针来连接新节点)。所以,整体插入操作在最好情况下的时间复杂度为O(logN)。

最坏情况

  • 当二叉搜索树退化为链表时,插入操作需要先遍历链表找到合适的插入位置。例如,若按照从小到大的顺序插入节点,要插入一个新的最大值,需要遍历到链表的末尾。此时,插入操作的时间复杂度为 O(N)。

问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插入关键码,二叉搜索树的性能都能达到最优?那么就有我们后续学习的AVL树和红黑树。

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

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

相关文章

visual studio设置修改文件字符集方法

该方法来自网文&#xff0c;特此记录备忘。 添加两个组件&#xff0c;分别是Force UTF-8,FileEncoding。 截图如下&#xff1a; 方法如下&#xff1a;vs中点击“扩展”->“管理扩展”&#xff0c;输入utf搜索&#xff0c;安装如下两个插件&#xff0c;然后重启vs&#xf…

MongoDB 安装教程(MAC版本)

1.官网地址 https://www.mongodb.com/ 下载社区版&#xff0c;并且解压即可 2.安装位置 没有固定位置&#xff0c;将解压后的文件拷贝到任意位置&#xff0c;这里将以 /usr/locall为例。 3.配置环境变量 ## 1.打开环境配置文件 open .bash_profile ## 2.添加环境配置&#…

input子系统的框架和重要数据结构详解

#1024程序员节 | 征文# 往期内容 I2C子系统专栏&#xff1a; 专栏地址&#xff1a;IIC子系统_憧憬一下的博客-CSDN博客具体芯片的IIC控制器驱动程序分析&#xff1a;i2c-imx.c-CSDN博客 – 末篇&#xff0c;有往期内容观看顺序 总线和设备树专栏&#xff1a; 专栏地址&#…

【人工智能】掌握深度学习中的时间序列预测:深入解析RNN与LSTM的工作原理与应用

深度学习中的循环神经网络&#xff08;RNN&#xff09;和长短时记忆网络&#xff08;LSTM&#xff09;在处理时间序列数据方面具有重要作用。它们能够通过记忆前序信息&#xff0c;捕捉序列数据中的长期依赖性&#xff0c;广泛应用于金融市场预测、自然语言处理、语音识别等领域…

RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器

RSocket vs WebSocket&#xff1a;Spring Boot 3.3 中的两大实时通信利器 随着现代互联网应用的不断发展&#xff0c;实时通信已经成为许多应用程序不可或缺的功能。无论是社交网络、在线游戏还是数据监控系统&#xff0c;实时通信都能提供快速、无缝的信息交换。而实现实时通…

高精度KEITHLEY2636A参数资料吉时利2636B数字源表

Keithley 2636A吉时利2636B数字源表&#xff0c;200V&#xff0c;1fA/1uV&#xff0c;2 通道&#xff0c;10A 脉冲 Keithley 2636A SourceMeter 是 Keithley 最新 IV 源测量仪器的一部分&#xff0c;可用作台式 IV 表征工具或多通道 IV 测试系统的构建块组件。对于台式使用&am…

STM32通信协议-I2C

目录 一&#xff0c;IC2的协议规则 I2C总线是PHILIPS公司开发的两线式串行总线&#xff0c;I2C总线主要解决了单片机一对多通信的问题 两根通信线&#xff1a;SCL,SDA&#xff0c;同步&#xff0c;半双工通信&#xff0c;支持数据应答机制&#xff0c;支持总线挂载多设备。 …

Python异常检测- 单类支持向量机(One-Class SVM)

系列文章目录 Python异常检测- Isolation Forest&#xff08;孤立森林&#xff09; python异常检测 - 随机离群选择Stochastic Outlier Selection (SOS) python异常检测-局部异常因子&#xff08;LOF&#xff09;算法 Python异常检测- DBSCAN 文章目录 系列文章目录前言一、On…

图像高清化(论文复现)

图像高清化(论文复现) 本文所涉及所有资源均在传知代码平台可获取 文章目录 图像高清化(论文复现)概述算法原理核心逻辑效果演示使用方式概述 本文复现论文 “Zero-Shot” Super-Resolution using Deep Internal Learning[1] 提出的图像超分辨率方法。 图像超分辨率是指从低…

如何从模块内部运行 Pytest

在 Python 中&#xff0c;pytest 是一个强大的测试框架&#xff0c;用于编写和运行测试用例。通常我们会在命令行中运行 pytest&#xff0c;但是有时你可能希望从模块或脚本的内部运行 pytest&#xff0c;比如为了自动化测试或集成到某个工作流程中。 1、问题背景 当你从模块…

Netty无锁化设计之对象池实现

池化技术是比较常见的一种技术&#xff0c;在平时我们已经就接触很多了&#xff0c;比如线程池&#xff0c;数据库连接池等等。当我们要使用一个资源的时候从池中去获取&#xff0c;用完就放回池中以便其他线程可以使用&#xff0c;这样的目的就是为了减少资源开销&#xff0c;…

JMeter 动态参数赋值实践

目录 前言 单线程 用户参数 场景说明 实战结果 配置明细 单线程 CSV Data Set Config 场景说明 实践结果 配置明细 多线程循环单次执行 场景说明 实践结果 配置明细 单线程 控制器 用户自定义变量 用户参数 场景说明 实战结果 配置明细 多并发 多接口 …

AudioSegment 提高音频音量 - python 实现

一些采集的音频声音音量过小可以通过 AudioSegment 实现音量增强。 按照 python 库&#xff1a; pip install AudioSegment 代码具体实现&#xff1a; #-*-coding:utf-8-*- # date:2024-10 # Author: DataBall - XIAN # Function: 音频增加音量import os from pydub import …

Matlab学习01-矩阵

目录 一&#xff0c;矩阵的创建 1&#xff0c;直接输入法创建矩阵 2&#xff0c;利用M文件创建矩阵 3&#xff0c;利用其它文本编辑器创建矩阵 二&#xff0c;矩阵的拼接 1&#xff0c;基本拼接 1&#xff09; 水平方向的拼接 2&#xff09;垂直方向的拼接 3&#xf…

记录:网鼎杯2024赛前热身WEB01

目录扫描&#xff0c;发现上传点&#xff0c;判断可能存在文件上传漏洞&#xff0c;并根据文件后缀判断网站开发语言为php 编写蚁剑一句话木马直接上传 蚁剑连接 这里生成 的flag是随机的&#xff0c;因为烽火台反作弊会随机生成环境&#xff0c;在一顿查找后&#xff0c;在hom…

stm32F103 实现呼吸灯效果

目录 硬件连接 软件实现步骤 初始化系统时钟。 配置 GPIO 引脚。 配置定时器以生成 PWM 信号。 在主循环中调整 PWM 占空比以实现呼吸效果。 示例代码 1. 初始化系统时钟 2. 配置 GPIO 引脚 3. 配置定时器以生成 PWM 信号 4. 在主循环中调整 PWM 占空比以实现呼吸效…

5G RedCap工业路由器赋能电力物联网应用

随着5G轻量化技术应用的推进&#xff0c;5G RedCap旨在提供低功耗、低成本、广覆盖等功能特点赋能电力智能化升级。特别适用于工业物联网、低空经济、车联网、消费电子和轻量级5G的需求。 5G RedCap工业路由器的特点 低功耗&#xff1a;5G RedCap工业路由器通过节能技术&#…

npm run serve 提示异常Cannot read property ‘upgrade‘ of undefined

npm run serve 提示Cannot read property ‘upgrade’ of undefined 一般是proxy的target代理域名问题导致的&#xff0c;如下&#xff1a; 解决方案&#xff1a; proxy: { “/remoteDealerReportApi”: { target: ‘http://demo-.com.cn’, //此域名有问题&#xff0c;会导致…

PTA数据库编程练习合集

10-1 查询重量在[40,65]之间的产品信息 本题目要求编写SQL语句&#xff0c; 检索出product表中所有符合40 < Weight < 65的记录。 提示&#xff1a;请使用SELECT语句作答。 表结构: CREATE TABLE product (Pid varchar(20), --商品编号PName varchar(50), --商品名…

JavaWeb开发7

前后端混合开发 沟通成本高 分工不明确 不便管理 不便维护扩展 前后端分离开发 前端--接口--后端 需求分析--接口定义--前后端并行开发--测试--前后端连调测试 前端开发 模块化 JS、CSS 组件化 UI结构、样式、行为 规范化 目录结构、编码、接口 自动化 构建、部署、…