当前位置: 首页 > news >正文

【C++数据结构】二叉树搜索树【完整版】

目录

一、二叉搜索树的定义

 二、二叉搜索树的实现:

1、树节点的创建--BSTreeNode

 2、二叉搜索树的基本框架--BSTree

3、插入节点--Insert

 4、中序遍历--InOrder

5、 查找--Find

6、 删除--erase

完整代码:

三、二叉搜索树的应用

1、key的模型 :判断在不在

2、key/value的模型:通过key找value 

key/value的应用场景

应用场景1--中英文互译

应用场景2--统计水果出现次数

 四、二叉搜索树性能分析


一、二叉搜索树的定义

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

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

 二、二叉搜索树的实现:

这里最好不用递归,递归比非递归更复杂,故用非递归实现

分两个文件:

BSTree.hpp(因为要用模板实现,而模板的实现和声明要放在一起的,若用模板实现就可用.hpp为后缀和 Test.c

1、树节点的创建--BSTreeNode

 是由节点组成的,故应写个BSTreeNode用来表示每个树节点,_left表示左指针,_right表示右指针,还有一个位置用来存值_key,因为无法确定存的是什么类型的值,故用模板来实现通用,设置成struct是因为树的节点对外是公开的,外部都可以访问的

template<class K>
struct BSTreeNode
{BSTreeNode(const K& key):_key(key), _left(nullptr), _right(nullptr){}BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;
};

 2、二叉搜索树的基本框架--BSTree

对于树的成员变量,一个根节点即可

template<class K>
class BSTree //Binary Search Tree
{typedef BSTreeNode<K> Node;
public:private:Node* _root = nullptr;可以直接定义,就一个成员变量,无需写个构造函数
};

3、插入节点--Insert

 这个函数需要有返回值的,以bool作为返回类型,因为这棵树中不允许数据冗余,即不能出现相同的数据。

插入就是用性质:左子树的值都比当前根节点的值小,右子树的值都比当前根节点的值大

若插入一个数据key,从根节点(用cur指针来表示当前位置)开始往下比就好了

①、如果key比当前节点的值大,那就接着往右走

②、如果key比当前节点的值小,那就接着往左走

对于①②直到找到一个空位置插入即可

③、如果走的过程中遇到相等的值,说明该key值不能插入,但要注意一个条件,如果这棵树本来就为空,那就直接把数据插入到根节点中就好

链接问题:

插入一个节点,必然要与树链接,若不链接,这个节点就是个临时数据,出了作用域就没了,但若把他链接到树上就能正常访问了,故这里采用双指针法cur表示当前节点,再定义一个parent,每次cur走之前,先把cur赋值给parent,这样最后cur走到空了,parent能记录到cur的上一位置,而这上一位置就是要找的cur要与其链接的位置,至于cur插入到parent的左还是右,若值比parent的值大,则插到右边,小,则插到左边

bool Insert(const K& key)
{if (_root == nullptr){//若为空树,就给它一个节点_root = new Node(key);//new是开空间+初始化,所以要调用构造函数,你要写的return true;}Node* cur = _root;//从根节点开始比较Node* parent = nullptr;while (cur){//都会找一个空位置插入,不会说挪动节点来进行插入if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//若在走的过程中遇到相同的数据,返回假,这个数据无法插入return false;}}cur = new Node(key);//向这个空位置插入数据//利用parent的位置与cur连接if (parent->_key > key)parent->_left = cur;//比根节点小,链接到左边elseparent->_right = cur;//比根节点大,链接到右边return true;
}

 4、中序遍历--InOrder

  这里用两个成员函数实现,为什么?中序遍历你要传树的根节点,而根节点就是类的私有成员变量,而你的中序遍历一定是在类外使用的,无法直接访问_root

解决方法:

法一、写个成员函数获得一下_root是可以的

法二、两个成员函数,即用InOrder来传这个_root,成员函数访问你_root一定是没问题的,那么_InOrder直接用来中序遍历即可,调用直接调用InOrder即可

void InOrder()
{_InOrder(_root);cout << endl;
}
//下面的可以放到private里面
void _InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}

下面利用写的插入中序遍历测试代码


void testTree()
{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、 查找--Find

bool Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_key > key)	{cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;//说明相等,则找到了,返回真}}return false;//走到空还没找到,说明没有此数据
}

6、 删除--erase

1、观察现象:  

删除2,让父亲指向我的右,删除8,让父亲指向我的右,5不好删,因为他有两个孩子

左为空,父亲指向我的右,右为空,父亲指向我的左,叶子节点可以归纳为左为空(右为空也行,这里就假设用左为空),因为叶子的左右都为空,它父亲的指向他的左还是右均可

左为空,

2、细节考虑

A、待删除节点左为空或右为空的情况(叶子结点可归类为左为空)

删除一个节点是让其父亲(Parent)的左指针还是右指针指向cur?

若cur的左子树为空】看cur到底是父亲的左子树还是右子树,若是父亲的左子树,则让父亲的左指向cur右子树 ,若为右子树,则让父亲的右指向cur的右子树

若cur的右子树为空】若是父亲的左子树,则让父亲的左指向cur左子树 ,若为右子树,则让父亲的右指向cur的左子树

B、待删除节点左右都不为空的情况

节点的左右子树都不为空,不能直接删除,直接删除会导致二叉搜索树混乱,故用替代法删除。

因为要符合左子树都比根节点小,右子树都比根节点大的性质,故要找左子树的最大节点或右子树的最小节点去替代它。(左子树最右边的节点是左子树最大节点,右子树的最左边的节点是右子树最小节点)【故假设我们下面就用右子树的最小节点】

比如删除7,可以用8(7的右子树的最左节点)来替代,那么替换完后,我删除这个7就可以直接删了,那么这个问题又转换到了被删除节点的左为空或者右为空,因为替换节点一定要么是最左边的节点要么是最右边的节点(不一定是叶子结点),那这个替换节点的左右子树一定存在左子树右子树有个为空的情况

所以删除 分三种情况

问题1:

删除一定要找到父亲,因为删完了还存在链接关系,所以单单用find去找是不行的,他找不到他的父亲节点,故还是用双指针法

 因为链接问题,所以删除关键看cur是在父亲的左还是右,而不是看cur的左边为空还是右边为空,这不符合所有场景

问题2:

最左节点不一定就是叶子结点,比如这里删除7,它的右子树的最左节点是8,则8替换完7后,8要被删除,他被删除完后,parent的右指针要指向rightMin的右节点

问题3:

parent初始值不能为nullptr,若删除7【che指针指向7】,因为要删除cur,Rightmin刚上来就=8,Rightmin的左子树为空,while循环都没进去,而parent它还是nullptr,那后续的链接肯定会有问题的,所以parent应该一上来就赋值为cur,而不是nullptr

问题4:

若要删除的节点是根节点,也要特别考虑,左为空,则让根=它的右节点,右为空,则让根=它的左节点

bool Erase(const K& key)
{Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//找到了,开始删除//1.左为空if (cur->_left == nullptr){if (cur == _root)_root = cur->_right;else{if (parent->_left == cur)parent->_left = cur->_right;//cur在父亲的左边,就让父亲的左指向cur的左elseparent->_right = cur->_right;//cur在父亲的右边,就让父亲的右指向cur的右}delete cur;}//2.右为空else if (cur->_right == nullptr){if (cur == _root)_root = cur->_left;else{if (parent->_right == cur)parent->_right = cur->_left;//cur在父亲的右边,就让父亲的右指向cur的左elseparent->_left = cur->_left;//cur在父亲的左边,就让父亲的左指向cur的右}delete cur;}//3.左右都不为空else{//找左子树的最右节点或右子树的最小节点去替代//这里用右子树的最小节点来替代Node* parent = cur;Node* Rightmin = cur->_right;//若用右树的最小节点,即右树最左节点while (Rightmin->_left){//最左节点的左子树一定为空,故为判断条件parent = Rightmin;//替换节点不一定是叶子结点,故还要用parent来链接Rightmin = Rightmin->_left;}cur->_key = Rightmin->_key;//用cur的值来替代//转换成删除Rightmin//若它是parent的右子树,则父亲的右指向它的右//若它是parent的左子树,则父亲的左指向它的左if (Rightmin == parent->_left)parent->_left = Rightmin->_right;elseparent->_right = Rightmin->_right;delete Rightmin;}return true;}}return false;//cur都为空了还没找到,则该数据不存在
}

完整代码:

BSTree.hpp

#pragma once
#include<iostream>
using namespace std;template<class K>
struct BSTreeNode
{BSTreeNode(const K& key):_key(key), _left(nullptr), _right(nullptr){}BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;};
template<class K>
class BSTree //Binary Search Tree
{typedef BSTreeNode<K> Node;
public:bool Insert(const K& key){if (_root == nullptr){//若为空树,就给它一个节点_root = new Node(key);//new是开空间+初始化,所以要调用构造函数,你要写的return true;}Node* cur = _root;//从根节点开始比较Node* parent = nullptr;while (cur){//都会找一个空位置插入,不会说挪动节点来进行插入if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//若在走的过程中遇到相同的数据,返回假,这个数据无法插入return false;}}cur = new Node(key);//向这个空位置插入数据//利用parent的位置与cur连接if (parent->_key > key)parent->_left = cur;//比根节点小,链接到左边elseparent->_right = cur;//比根节点大,链接到右边return true;}bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key)	{cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;//说明相等,则找到了,返回真}}return false;}bool Erase(const K& key){Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//找到了,开始删除//1.左为空if (cur->_left == nullptr){if (cur == _root)_root = cur->_right;else{if (parent->_left == cur)parent->_left = cur->_right;//cur在父亲的左边,就让父亲的左指向cur的左elseparent->_right = cur->_right;//cur在父亲的右边,就让父亲的右指向cur的右}delete cur;}//2.右为空else if (cur->_right == nullptr){if (cur == _root)_root = cur->_left;else{if (parent->_right == cur)parent->_right = cur->_left;//cur在父亲的右边,就让父亲的右指向cur的左elseparent->_left = cur->_left;//cur在父亲的左边,就让父亲的左指向cur的右}delete cur;}//3.左右都不为空else{//找左子树的最右节点或右子树的最小节点去替代//这里用右子树的最小节点来替代Node* parent = cur;Node* Rightmin = cur->_right;//若用右树的最小节点,即右树最左节点while (Rightmin->_left){//最左节点的左子树一定为空,故为判断条件parent = Rightmin;//替换节点不一定是叶子结点,故还要用parent来链接Rightmin = Rightmin->_left;}cur->_key = Rightmin->_key;//用cur的值来替代//转换成删除Rightmin//若它是parent的右子树,则父亲的右指向它的右//若它是parent的左子树,则父亲的左指向它的左if (Rightmin == parent->_left)parent->_left = Rightmin->_right;elseparent->_right = Rightmin->_right;delete Rightmin;}return true;}}return false;//cur都为空了还没找到,则该数据不存在}void InOrder(){_InOrder(_root);cout << endl;}//下面的可以放到private里面void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}private:Node* _root = nullptr;//可以直接定义,就一个成员变量,无需写个构造函数
};void testTree()
{BSTree<int> t;int a[] = { 5,3,4,1,7,8,2,6,0,9 };for (auto e : a){//数组是可以用迭代器来遍历的t.Insert(e);//插入节点到树中}t.InOrder();//中序遍历
}

 Test.cpp

#include"BSTree.hpp"int main()
{testTree();return 0;
}

三、二叉搜索树的应用

搜索树使用场景:

1、key的模型 :判断在不在

 比如进入校园要刷校园卡,卡本质里面有芯片,芯片上存储信息,把学校所有学员的信息存到二叉搜索树(因为他的查找效率很高),然后用机器扫描卡,看你卡的信息是否在我的树中,在就让你进

2、key/value的模型:通过key找value 

①、高铁刷身份证

买了票就能进站,刷身份证读的是身份证号码,【key就是身份证,value就是票的信息】然后通过身份证到后台服务器查是否有票的信息,是否是这个车站,这个车次等等,即通过身份证找value

②、中英文互译

中文就是key,英文就是value,即通过中文找英文或通过英文找中文。

③、统计次数

统计次数,即通过一个值找另一个值,用搜索树实现的原因是二叉搜索树的效率高,搜索快

key/value模型的实现只需在我们实现的二叉搜索树中改动一下代码即可,即节点里面除了有key,还有value,但是比较大小的过程还是用key来比较,和value没关系,找到了key就相当于找到了value,因为两者在同一节点中,还要修改的就是Find函数,返回值变成返回节点的指针而不是bool值,因为这样返回的节点既有key又有value

注意:

对于搜索树的修改,搜索树中key是不允许修改的

如果是kv模型的搜索树,可以修改value,但不能修改key,就是因为你改了key就不一定满足二叉搜索树的条件了

kv模型的完整代码:

BSTree.hpp :

//key/value模型
#include<iostream>
#include<string>
using namespace std;template<class K, class V>
struct BSTreeNode
{BSTreeNode(const K& key,const V& value):_key(key),_value(value), _left(nullptr), _right(nullptr){}BSTreeNode<K,V>* _left;BSTreeNode<K,V>* _right;K _key;V _value;};
template<class K, class V>
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);//new是开空间+初始化,所以要调用构造函数,你要写的return true;}Node* cur = _root;//从根节点开始比较Node* parent = nullptr;while (cur){//都会找一个空位置插入,不会说挪动节点来进行插入if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//若在走的过程中遇到相同的数据,返回假,这个数据无法插入return false;}}cur = new Node(key,value);//向这个空位置插入数据//利用parent的位置与cur连接if (parent->_key > key)parent->_left = cur;//比根节点小,链接到左边elseparent->_right = cur;//比根节点大,链接到右边return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return cur;//说明相等,则找到了,返回真}}return nullptr;}bool Erase(const K& key){Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//找到了,开始删除//1.左为空if (cur->_left == nullptr){if (cur == _root)_root = cur->_right;else{if (parent->_left == cur)parent->_left = cur->_right;//cur在父亲的左边,就让父亲的左指向cur的左elseparent->_right = cur->_right;//cur在父亲的右边,就让父亲的右指向cur的右}delete cur;}//2.右为空else if (cur->_right == nullptr){if (cur == _root)_root = cur->_left;else{if (parent->_right == cur)parent->_right = cur->_left;//cur在父亲的右边,就让父亲的右指向cur的左elseparent->_left = cur->_left;//cur在父亲的左边,就让父亲的左指向cur的右}delete cur;}//3.左右都不为空else{//找左子树的最右节点或右子树的最小节点去替代//这里用右子树的最小节点来替代Node* parent = cur;Node* Rightmin = cur->_right;//若用右树的最小节点,即右树最左节点while (Rightmin->_left){//最左节点的左子树一定为空,故为判断条件parent = Rightmin;//替换节点不一定是叶子结点,故还要用parent来链接Rightmin = Rightmin->_left;}cur->_key = Rightmin->_key;//用cur的值来替代//转换成删除Rightmin//若它是parent的右子树,则父亲的右指向它的右//若它是parent的左子树,则父亲的左指向它的左if (Rightmin == parent->_left)parent->_left = Rightmin->_right;elseparent->_right = Rightmin->_right;delete Rightmin;}return true;}}return false;//cur都为空了还没找到,则该数据不存在}void InOrder(){_InOrder(_root);cout << endl;}//下面的可以放到private里面void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" <<root->_value << endl;_InOrder(root->_right);}private:Node* _root = nullptr;//可以直接定义,就一个成员变量,无需写个构造函数
};void testTree1()
{BSTree<string, string>dict;//字典dict.Insert("sort", "排序");dict.Insert("polynomial", "多项式");dict.Insert("femininity", "女性");string str;while (cin >> str){BSTreeNode<string, string>* ret = dict.Find(str);if (ret){cout << ret->_value << endl;}else{cout << "无此单词" << endl;}}
}void testTree2()
{string strArr[] = { "西瓜","西瓜","香蕉","樱桃","西瓜","西瓜","香蕉" };BSTree<string, int> countTree;//key是string,value是intfor (auto str : strArr){BSTreeNode<string, int>* ret = countTree.Find(str);if (ret == nullptr){//第一次出现,就插入这个水果,出现一次,因为一开始树为空countTree.Insert(str, 1);}else{//出现过了,就++次数ret->_value++;}}countTree.InOrder();
}

 Test.cpp

#include"BSTree.hpp"int main()
{//testTree1();testTree2();return 0;
}

key/value的应用场景

应用场景1--中英文互译

key/value模型测试下面代码逻辑(中英文互译

 

应用场景2--统计水果出现次数

有一堆水果,请你统计水果出现的次数

 四、二叉搜索树性能分析

 

如果插入的数据是有序的或者接近有序的,那么搜索树效率就完全没办法保障

如:1  2  3  4  5  6  7  8,对于树就变成了单支树,搜索树的效率最坏的情况下是O(N)

如何解决?平衡树1、AVLTree   2、红黑树

相关文章:

【C++数据结构】二叉树搜索树【完整版】

目录 一、二叉搜索树的定义 二、二叉搜索树的实现&#xff1a; 1、树节点的创建--BSTreeNode 2、二叉搜索树的基本框架--BSTree 3、插入节点--Insert 4、中序遍历--InOrder 5、 查找--Find 6、 删除--erase 完整代码&#xff1a; 三、二叉搜索树的应用 1、key的模型 &a…...

TouchGFX之字体缓存

使用二进制字体需要将整个字体加载到存储器。 在某些情况下&#xff0c;如果字体很大&#xff0c;如大字号中文字体&#xff0c;则这样做可能不可取。 字体缓存使应用能够从外部存储器只能加载显示字符串所需的字母。 这意味着整个字体无需保存到在可寻址闪存或RAM上&#xff…...

windows系统关闭软件开机自启的常用两种方法

win10中安装软件时经常会默认开机自启动&#xff0c;本文主要介绍两种关闭软件开机自启动方法。 方法1 通过任务管理器设置 1.在任务管理器中禁用开机自启动&#xff1a;打开任务管理器&#xff0c;右键已启动的软件&#xff0c;选择禁用。 方法2 通过windows服务控制开机自启…...

巧用@Conditional注解根据配置文件注入不同的bean对象

项目中使用了mq&#xff0c;kafka两种消息队列进行发送数据&#xff0c;为了避免硬编码&#xff0c;在项目中通过不同的配置文件自动识别具体消息队列策略。这里整理两种实施方案&#xff0c;仅供参考&#xff01; 方案一&#xff1a;创建一个工具类&#xff0c;然后根据配置文…...

论文笔记(整理):轨迹相似度顶会论文中使用的数据集

0 汇总 数据类型数据名称数据处理出租车数据波尔图 原始数据&#xff1a;2013年7月到2014年6月&#xff0c;170万条数据 ICDE 2023 Contrastive Trajectory Similarity Learning with Dual-Feature Attention 过滤位于城市&#xff08;或国家&#xff09;区域之外的轨迹 过…...

Python实现单例模式

使用函数装饰器 def singleton(cls):_instance {}def inner():if cls not in _instance:_instance[cls] cls()return _instance[cls]return innersingleton class Demo(object):def __init__(self):passdef test():b1 Demo()b2 Demo()print(b1, b2)使用类装饰器 class si…...

spark相关网站

Spark的五种JOIN策略解析 https://www.cnblogs.com/jmx-bigdata/p/14021183.html 万字详解整个数据仓库建设体系&#xff08;好文值得收藏&#xff09; https://mp.weixin.qq.com/s?__bizMzg2MzU2MDYzOA&mid2247484692&idx1&snf624672e62ba6cd4cc69bdb6db28756a&…...

ThreeJS-3D教学四-光源

three模拟的真实3D环境&#xff0c;一个非常炫酷的功能便是对光源的操控&#xff0c;之前教学一中已经简单的描述了多种光源&#xff0c;这次咱们就详细的讲下一些最常见的光源&#xff1a; AmbientLight 该灯光在全局范围内平等地照亮场景中的所有对象。 该灯光不能用于投射阴…...

Linux 回收内存到底怎么计算anon/file回收比例,只是swappiness这么简单?

概述 Linux内核为了区分冷热内存,将page以链表的形式保存,主要分为5个链表,除去evictable,我们主要关注另外四个链表:active file/inactive file,active anon和inactive anon链表,可以看到这主要分为两类,file和anon page,内存紧张的时候,内核开始从inactive tail定…...

软件测试中的测试工具和自动化测试

1. 测试工具 测试工具也分为不同人员使用的 开发人员&#xff1a;测试框架&#xff0c;编写测试用例&#xff1b;各类线上dump分析工具如windgb&#xff1b;开发时的集成IDE工具如Visual Studio&#xff0c;idea等等 面向不同测试需求的测试工具 软件测试是软件开发生命周期…...

个人博客系统测试报告

个人博客系统测试报告 一.项目背景二.项目功能三.测试用例3.1 功能测试3.2 自动化测试&#xff08;部分测试&#xff09;3.2.1登陆页面3.2.2博客详情页3.2.3博客编辑页3.2.4个人列表页3.2.5测试结果 3.3 性能测试 一.项目背景 当学习完一项技能后&#xff0c;我们总会习惯通过博…...

高效搜索,提升编程效率

一、搜索效率 1.1魔法上网 网址&#xff1a; 一个很变态但可以让你快速学会计算机的方法…………_哔哩哔哩_bilibili 谷歌镜像&#xff1a; https://search.fuyeor.com/zh-cn/Google 谷歌学术&#xff1a; https://link.zhihu.com/?targethttps%3A//scholar.lanfanshu.cn/…...

Java编程技巧:文件上传、下载、预览

目录 1、上传文件1.1、代码1.2、postman测试截图 2、下载resources目录中的模板文件2.1、项目结构2.2、代码2.3、使用场景 3、预览文件3.1、项目结构3.2、代码3.3、使用场景 1、上传文件 1.1、代码 PostMapping("/uploadFile") public String uploadFile(Multipart…...

【蓝桥杯选拔赛真题63】Scratch云朵降雨 少儿编程scratch图形化编程 蓝桥杯选拔赛真题解析

目录 scratch云朵降雨 一、题目要求 编程实现 二、案例分析 1、角色分析...

【新版】系统架构设计师 - 软件架构的演化与维护

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 软件架构的演化与维护考点摘要软件架构演化和定义面向对象软件架构演化对象演化消息演化复合片段演化约束演化 软件架构演化方式静态演化动态演化 软件架构演化原则软件架构演化评估方法大型网站架…...

安卓循环遍历计时器

计时器循环遍历 计时器的使用 我习惯两种方式如下&#xff1a; 第一种使用 handler&#xff1a; 1&#xff0c;初始化 声明 public static final int REGULAR_TIME 1000; //1秒 时间间隔private Handler mUiHandler;private int index0;Runnable runnable new Runnable()…...

Docker-基本了解

Docker-基本了解 一、基本概念1、镜像2、容器 二、执行流程三、体系结构 一、基本概念 Docker是容器化平台&#xff0c;提供应用打包&#xff0c;部署与运行应用的容器化平台&#xff0c;应用程序通过docker engine&#xff08;Docker 引擎获取可用资源&#xff09;&#xff0…...

Leetcode383. 赎金信

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每…...

overleaf杂谈-Springer文献格式问题

目录 overleaf写作问题记录1.Latex中的%问题&#xff08;文本变成灰色&#xff09;2.Springer文献格式问题2.1 新建reference.bib2.2 谷歌学术搜索文章并引用2.3 复制BibTex2.4 复制进reference.bib2.5 在sn-article.tex的\end{document}前添加语句2.6 引用文献2.7 Springer模板…...

No148.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

BASH shell脚本篇4——函数

这篇文章介绍下BASH shell中的函数。之前有介绍过shell的其它命令&#xff0c;请参考&#xff1a; BASH shell脚本篇1——基本命令 BASH shell脚本篇2——条件命令 BASH shell脚本篇3——字符串处理 函数是代码重用的最重要方式。Bash函数可以定义为一组命令&#xff0c;在b…...

VisualStudio配置OpenCV环境

VS2022配置OpenCV环境 记录一下Windows上VS配置OpenCV环境的过程。&#xff08;VS2022 OpenCV4.8&#xff09; 一、下载OpenCV 从官网或者镜像网站下载Windows版OpenCV。4.8版本的文件为opencv-4.8.0-windows.exe 双击解压到自定义目录&#xff0c;我这边是&#xff1a;E:…...

C++手写NMS

文章目录 前言一、NMS是什么&#xff1f;二、代码展示三、代码实现思路总结 前言 目标检测模型推理后&#xff0c;一般都需要进行NMS操作进行多余框去重&#xff0c;板端部署一般不用opencv自带的NMS&#xff0c;所以记录下手写NMS的代码。 一、NMS是什么&#xff1f; 非极大…...

第9讲:VUE中监听器WATCH使用详解

目录 监听器介绍 监听普通属性 监听对象属性 监听路由属性监听器watch 监听器:它是侦听属性值或者计算属性的变化,一旦发生变化可以在函数中进行相应的操作,从而达到change事件监听的效果!监听器是一个对象,以 key-value 的形式表示。key 是需要监听的表达式,value 是对…...

微信小程序开发基础(一)认识小程序

微信小程序&#xff0c;小程序的一种&#xff0c;英文名Wechat Mini Program&#xff0c;是一种不需要下载安装即可使用的应用&#xff0c;它实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或搜一下即可打开应用。微信小程序是一种不用下载就能使用的应用&#xff0c;也是…...

LeetCode 1049. 最后一块石头的重量 II

1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&am…...

Golang中的类型转换介绍

Golang中存在4种类型转换&#xff0c;分别是&#xff1a;断言、显式、隐式、强制。下面我将一一介绍每种转换使用场景和方法 一、断言类型转换 主要是判断变量是否可以转换成某一类型。断言主要用于变量是interface{}类型&#xff08;接口类型&#xff09;的情况&#xff0c;…...

本人碰到的RN项目的坑

1.路径问题 路径不能含有中文 2.下载jar\aar包超时问题 手动下载:任意位置新建个文件夹,然后点击超时的jar包链接跳转到浏览器后下载到这个文件夹内,返回报错的地方找到报错的包名(com或者org开头的),然后去这个路径下找到对应的包名 C:\Users\22560\.gradle\caches\module…...

EcmaScript标准-导入与导出-js

ECMAScript是一种由Ecma国际&#xff08;前身为欧洲计算机制造商协会&#xff0c;European Computer Manufacturers Association&#xff09;通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛&#xff0c;它往往被称为JavaScript或JScript&#xff0c;所以它…...

如何将matlab中的mat矩阵文件在python中读取出来

先安装hdf5storage这个包 pip3 install hdf5storage 然后在当前目录下放入要读取的mat文件 # 将matlab中的mat文件读取出来 import hdf5storagedata hdf5storage.loadmat(inputWeights.mat) print(data[inputWeights])...

电子商务网站开发流程图/怎么网站推广

jq清除select框的数据最近在接触 jq 的项目&#xff0c;之前都没有写过&#xff0c;最近遇到一个不知道怎么写的东西&#xff0c;记录一下 $(#id).val().trigger(change)...

网站建设方案模板高校/东莞今日头条最新消息

09 Eclipse设置代码注释模版背景博客正文背景 在团队协作开发的项目中&#xff0c;为了降低沟通和维护成本&#xff0c;项目组成员使用统一的编码规范和注释规范显得尤为重要。本文就说一说如果在Eclipse中设置代码注释模版&#xff0c;技术经理可以要求所有的开发人员设置为统…...

wordpress评论可见内容/国内新闻最近新闻今天

IntelliJ IDEA简介 IDEA 全称IntelliJ IDEA&#xff0c;是用于java语言开发的集成环境&#xff08;也可用于其他语言&#xff09;&#xff0c;IntelliJ在业界被公认为最好的java开发工具之一&#xff0c;尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合…...

容桂最新消息/吉林网络seo

1082. Read Number in Chinese (25) 时间限制400 ms内存限制65536 kB代码长度限制16000 B判题程序Standard作者CHEN, YueGiven an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese way. Output "Fu" first if it is ne…...

购物网站建设优缺点/百度搜索风云榜小说排行榜

CRM是最常用的后台管理系统之一&#xff0c;以下为CRM的原型设计思路及框架 基本页面axure&#xff1a; 链接: https://pan.baidu.com/s/1tcuVdUw0f9jO4h4D-TPRJQ 密码: tj4h 基本组件axure&#xff1a; 链接: https://pan.baidu.com/s/1zVN-626LW6g24ioqgzmPcw 密码: suqf...

wordpress 下载官网/深圳百度竞价托管公司

我有2个进程在不同的机器上运行,它们通过TCP套接字进行通信.这两个进程都具有既充当服务器又充当客户端的代码.即ProcessA打开了一个服务器套接字,它在portX上绑定,ProcessB在portY上打开了一个服务器套接字绑定.ProcessA打开客户端套接字以连接ProcessB并开始作为客户端发送消…...