【C++第三方库】快速上手---轻量级数据库SQLite和单元测试工具Gtest

每日激励,“驾驭命运的舵是奋斗。不抱有幻想,不放弃一点机会,不停止一日努力。”

绪论​:
本篇文章将写道如何快速的上手Gtest和SQLite第三方库,这两个第三方库都是在项目编写过程中非常重要的
——————
话不多说安全带系好,发车啦(建议电脑观看) 。


SQLite3

SQLite是⼀个进程内的轻量级数据库,它实现了⾃给⾃⾜的、⽆服务器的、零配置的、事务性的 SQL数据库引擎。它是⼀个零配置的数据库,这意味着与其他数据库不⼀样,我们不需要在系统中配置。
像其他数据库,SQLite 引擎不是⼀个独⽴的进程,可以按应⽤程序需求进⾏静态或动态连接,SQLite直接访问其存储⽂件(很多app中都是用了该数据库)

  • 不需要⼀个单独的服务器进程或操作的系统(⽆服务器的
  • SQLite 不需要配置
  • ⼀个完整的 SQLite 数据库是存储在⼀个单⼀的跨平台的磁盘⽂件
  • SQLite 是⾮常⼩的,是轻量级的,完全配置时⼩于 400KiB,省略可选功能配置时⼩于250KiB
  • SQLite 是⾃给⾃⾜的,这意味着不需要任何外部的依赖
  • SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问
  • SQLite ⽀持 SQL92(SQL2)标准的⼤多数查询语⾔的功能
  • SQLite 使⽤ ANSI-C 编写的,并提供了简单和易于使⽤的 API
  • SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运
    ⾏(跨平台的

常用接口:

1. 查看当前数据库在编译阶段是否启动了线程安全:

int sqlite3_threadsafe(); 0:未启⽤; 1:启⽤
需要注意的是sqlite3是有三种安全等级的:1. ⾮线程安全模式2. 线程安全模式(不同的连接在不同的线程/进程间是安全的,即⼀个句柄不能⽤于多线程间)3. 串⾏化模式(可以在不同的线程/进程间使⽤同⼀个句柄)

2. 创建/打开数据库⽂件,并返回操作句柄

操作句柄:ppDbint sqlite3_open(const char *filename, sqlite3 **ppDb)   成功返回SQLITE_OK若在编译阶段启动了线程安全,则在程序运⾏阶段可以通过参数选择线程安全等级int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const
char *zVfs );
返回:SQLITE_OK表⽰成功
flag(宏)选项(代表线程 安全等级): SQLITE_OPEN_READWRITE -- 以可读可写⽅式打开数据库⽂件SQLITE_OPEN_CREATE -- 不存在数据库⽂件则创建
SQLITE_OPEN_NOMUTEX--多线程模式,只要不同的线程使⽤不同的连接即可保证线程
安全
SQLITE_OPEN_FULLMUTEX--串⾏化模式 (一般使用这个!!)int sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*,int,char**,char**), void* arg, char **err)
返回:SQLITE_OK表⽰成功/反之是出错的
传进去的回调函数:int (*callback)(void*,int,char**,char**)void* : 是设置的在回调时传⼊的arg参数int:⼀⾏中数据的列数char**:存储⼀⾏数据的字符指针数组char**:每⼀列的字段名称这个回调函数有个int返回值,成功处理的情况下必须返回0,返回⾮0会触发ABORT(异常)退出程序

3. 销毁句柄:

 int sqlite3_close(sqlite3* db); 成功返回SQLITE_OKint sqlite3_close_v2(sqlite3*); 推荐使⽤--⽆论如何都会返回SQLITE_OK

4. 获取错误信息:

const char *sqlite3_errmsg(sqlite3* db);

实操(简单封装SQLit3来使用)

创建sqlite3目录下创建sqlite.hpp文件,封装实现一个sqliteHelper类,提供简单的sqlite数据库操作接口,完成数据的几乎增删查改操作

  1. 打开/创建数据库文件
  2. 针对打开的数据库执行操作(一库一文件)
    1. 表的操作
    2. 数据的操作
  3. 关闭数据库

头文件:sqlite3.h

SqliteHelper类

  1. 构造(dbfile)
    1. 初始化_dbfile、_handler设为空
  2. bool open(safe_leve = SQLITE_OPEN_FULLMUTEX)
    1. 使用int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const
      char *zVfs );
    2. int ret接收sqlite3_open_v2返回值,设置flag:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_leve,zvfs设为nullptr
    3. 失败ret != SQLITE_OK 打印:创建/打开sqlite数据库失败: 在打印:sqlite3_errmgs中查看错误
  3. exec(sql语句,SqliteCallback cb,arg)
    1. 重命名回调函数为SqliteCallback
    2. 调用sqlite3_exec执行(错误信息填null)
    3. 同样失败(!=SQLITE_OK):打印sql、执行失败、查看错误信息
  4. void close()
    1. 调用sqlite3_close_v2

成员变量:
成员句柄 _handler
数据库文件:_dbfile

测试使用

main:
创建SqliteHelper类gelper对象

  1. 创建/打开库文件
    1. assert:open(打开失败就断言)
  2. 创建表(不存在则创建),学生信息:学号,姓名,年龄
    1. ct:sql语句 “create table if not exists student(sn int primary key ,name vchar(32),age int);”;
    2. 调用exec(创建表不用回调)
  3. 新增数据,修改,删除,查询
    1. insert_sql:“insert into student values(1,小明,18),(2,‘小黑’,19),(3,‘小红’,18);”;
    2. select_sql:“select sn,name,age from student”
    3. assert exec(插入语句,回调设为空)
  4. 关闭数据库 close

makefile:略(注意连接sqlite3库)

sqlite数据库的使用:

  1. 打开数据库:使用sqlite3 db文件
  2. 使用.tables 查看表
  3. 使用sql语句查看 select * from student在这里插入图片描述

修改执行语句进行
修改:“update student set name=‘张小明’ where sn = 1;”;
删除:“delete from where sn = 3;”
查询:“select name from student”

  1. 创建变量arry(vector的用于储存查询到的的结果)
  2. 打印arry中的数据(循环)

不同了需要写回调函数(将数据保存到vector中):

回调函数格式:int (*callback)(void*,int,char**,char**)
1. void* 是外部传递进来的参数(通过强转使用)
2. int 是一行中的数据列数
3. 第一个char** 是储存每一行的字符指针数组
4. 第二个char** 是存储每一列的字段名称

select_stu_callback回调函数

  1. 将arg参数强转为vector* 得到外部的容器
  2. 然后将结果(只用储存第一个char** 中的第一行数据,因为查询结果只有一个)push到vector中
  3. 返回0(不然的话会导致abort异常)必须有!

sqllite3.hpp源码:

#include <iostream>
#include <string>
#include <sqlite3.h>
#include <vector>
#include <cassert>
#include "loger.hpp"class  SqliteHelper{
typedef int (*SqliteCallback)(void*,int,char**,char**);public:SqliteHelper(const std::string& dbfile):_dbfile(dbfile),_handler(nullptr){}//int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
bool open(int safe_leve = SQLITE_OPEN_FULLMUTEX)//SQLITE_OPEN_FULLMUTEX默认就为串行化模式
{int ret = sqlite3_open_v2(_dbfile.c_str(),&_handler,safe_leve | SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE,nullptr);//第一个参数是db文件路径//第二个参数是一个输出型变量,我们将sqlite的句柄传进去,获取open后db的句柄//第三个参数是文件打开的默认权限和方式 和 线程的安全等级//SQLITE_OPEN_CREATE: 不存在数据库⽂件则创建// SQLITE_OPEN_READWRITE -- 以可读可写⽅式打开数据库⽂件//第四个参数设为空即可if(ret != SQLITE_OK){ELOG( "创建/打开sqlite数据库失败:%s",sqlite3_errmsg(_handler));return false;}else{DLOG("打开成功");return true;}
}//提前设置 SqliteCallback ==  int (*SqliteCallback)(void*,int,char**,char**)回调函数
bool exec(const std::string& sql,SqliteCallback cb,void* arg){int ret = sqlite3_exec(_handler,sql.c_str(),cb,arg,nullptr);//if(ret != SQLITE_OK){std::cout << sql << std::endl;ELOG( "执行失败、查看错误信息: %s",sqlite3_errmsg(_handler));return false;}else{DLOG ("执行成功");return true;}
}bool close(){sqlite3_close_v2(_handler);//return true;
}private:std::string _dbfile;sqlite3 * _handler;
};

测试源码:


#include "sqllite3.hpp"
#include <cassert>
#include <iostream>
/*int:一行中有的属性个数(列数)char** 储存一行数据的字符指针数组char** 每一列的字段名称*/int Select(void* v,int,char** table,char** ){std::vector<std::string>* data = (std::vector<std::string>*) v;data->push_back(table[0]);//只有一个数据所以直接拿去table[0]return 0;//必须返回0,不然就会abort异常}int main()
{SqliteHelper sq("./test.db");assert(sq.open());// sq.exec("create table if not exists student(sn int primary key,name vchar(32),age int);",nullptr,nullptr);// sq.exec("insert into student values(3,'小明',18)",nullptr,nullptr);//插入不需要有回调std::vector<std::string> v;sq.exec("select sn,name,age from student",Select,&v);for (auto &name : v) {std::cout << name << std::endl;}   sq.close();return 0;
}

GTest单元测试框架

GTest是⼀个跨平台的 C++单元测试框架,由google公司发布。gtest是为了在不同平台上为编写C++单元测试⽽⽣成的。它提供了丰富的断⾔、致命和⾮致命判断、参数化等等。

GTest的使用

头文件:#include <gtest/gtest.h>

TEST的宏断言

TEST宏:

  1. TEST(test_case_name, test_name)
  2. TEST_F(test_fixture,test_name)
  • TEST:主要⽤来创建⼀个简单测试, 它定义了⼀个测试函数, 在这个函数中可以使⽤任何C++代码并且使⽤框架提供的断⾔进⾏检查

  • TEST_F:主要⽤来进⾏多样测试,适⽤于多个测试场景如果需要相同的数据配置的情况, 即相同的数据测不同的⾏为

GTest中的断⾔的宏可以分为两类:

  1. ASSERT_系列:如果当前点检测失败则退出当前函数
  2. EXPECT_系列:如果当前点检测失败则继续往下执⾏
// bool值检查
ASSERT_TRUE(参数),期待结果是true
ASSERT_FALSE(参数),期待结果是false
//数值型数据检查
ASSERT_EQ(参数1,参数2),传⼊的是需要⽐较的两个数 equal
ASSERT_NE(参数1,参数2)not equal,不等于才返回true
ASSERT_LT(参数1,参数2),less than,⼩于才返回true
ASSERT_GT(参数1,参数2),greater than,⼤于才返回true
ASSERT_LE(参数1,参数2),less equal,⼩于等于才返回true
ASSERT_GE(参数1,参数2),greater equal,⼤于等于才返回true

上述操作的宏都必须在TEST测试单元中使用

实操(使用断言的宏):

所需头文件:gtest/gtest.h

TEST(该测试名称,单元测试名称)
{使用宏
}main(argc、argv)
testing::InithGoogleTest(&argc、argv)//初始化单元测试
RUN_ALL_TESTS()运行所有单元测试
  1. 使用进行大于测试:ASSERT_GT:
    在这里插入图片描述

实操(俩种断言宏的区别):

  1. 小于测试:ASSERT_LT:
    在这里插入图片描述

发现OK没执行。

  1. 如果使用EXPECT替换ASSERT,就会打印OK
    在这里插入图片描述

发现OK执行了
总结:

因为断言宏的使用如下:
1. ASSERT_ 断言失败则直接退出
2. EXPECT_ 断言失败继续运行

事件机制

GTest中的事件机制是指在测试前和测试后提供给⽤⼾⾃⾏添加操作的机制,⽽且该机制也可以让同⼀测试套件下的测试⽤例共享数据。

GTest框架中事件的结构层次

  1. 测试中,可以有多个测试套件(可以理解为一组单元测试
  2. 测试套件:一个测试环境,可以在单元测试直接进行测试环境初始化,测试完毕后进行测试环境清理
  3. 全局测试套件在整体的测试中,只会初始化一次环境,在所有测试用例完毕后,才会清理
  4. 用例测试套件在每次的单元测试中,都会重新初始化测试环境,完毕后清理环境

全局测试套件:

全局事件:针对整个测试程序。实现全局的事件机制,需要创建⼀个⾃⼰的类,然后继承testing::Environment类,然后分别实现成员函数 SetUp 和 TearDown ,同时在main函数内进⾏调⽤ testing::AddGlobalTestEnvironment(new MyEnvironment); 函数添加全局的事件机制

如下:

class TestEnv : public testing::Environment {public:virtual void SetUp() override{}virtual void TearDown() override{ }
};

全局测试套件,其实就是用户定义一个全局的测试环境类
SetUp:在所有单元测试运行前执行的接口,常用测试环境进行初始化(注意他们是虚函数!
TearDown:在所有单元测试运行结束后执行的接口,用于环境清理

实操:

使用一个全局的map来测试使用:
全局初始化插入两个数据,然后再测试判断,然后删除,后再判断,来使用,查看失败的情况

全局事件类

std::unordered_map<std::string,std::string> _dict;
class HashTest : public testing::Environment{
public:virtual void SetUp() override{std::cout << "测试前:提前准备数据" << std::endl;_dict.insert(std::make_pair("hello","你好"));_dict.insert(std::make_pair("apple","苹果"));}virtual void TearDown()override{std::cout << "测试结束后:清理数据" << std::endl;_dict.clear();}
};

单元测试:

TEST(HashTest1, test1) {ASSERT_EQ(_dict.size(), 2);_dict.erase("hello");
}TEST(HashTest2_test1_Test, test1) {ASSERT_EQ(_dict.size(), 2);
}

主函数

  1. 初始化单元测试InitGoogleTest
  2. 添加全局测试:testing::AddGlobalTestEnvironment(new 全局测试套件类)
  3. 开始所有测试查看情况
int main(int argc,char* argv[])
{testing::InitGoogleTest(&argc,argv);testing::AddGlobalTestEnvironment(new HashTest);//调用AddGlobalTestEnvironment new 一个全局测试类RUN_ALL_TESTS();return 0;
}

在这里插入图片描述

分析:最终结果(因为在第一个测试后删除了一个元素,所以第二次测试时判断大小是否为2时就会报错)

用例(独立)测试事件(最重要的):

针对⼀个个测试套件。测试套件的事件机制我们同样需要去创建⼀个类,继承⾃testing::Test ,实现两个静态函数 SetUpTestCase 和 TearDownTestCase ,测试套件的事件机制不需要像全局事件机制⼀样在 main 注册(直接RUN_ALL_TESTS),⽽是需要将我们平时使⽤的 TEST 宏改为 TEST_F 宏

  1. SetUpTestCase() 函数:是在测试套件第⼀个测试⽤例开始前执⾏
  2. TearDownTestCase():函数是在测试套件最后⼀个测试⽤例结束后执⾏
  • 需要注意TEST_F的第⼀个参数是我们创建的类名,也就是当前测试套件的名称,这样在TEST_F宏的测试套件中就可以访问类中的成员了(也就是单元测试的名称 == 测试套件类名)。

具体如下图:

在这里插入图片描述

TestCase事件:

针对⼀个个测试⽤例。测试⽤例的事件机制的创建和测试套件的基本⼀样,不同地⽅在于测试⽤例实现的两个函数分别是 SetUp 和 TearDown , 这两个函数也不是静态函数

  1. SetUp():函数是在每⼀个测试⽤例的开始前执⾏
  2. TearDown():函数是在每⼀个测试⽤例的结束后执⾏

在TestSuite/TestCase事件中,每个测试⽤例,虽然它们同⽤同⼀个事件环境类,可以访问其中的资源(公共成员变量),但是本质上每个测试⽤例的环境都是独⽴的(也就是其成员变量的数据并不是共享的,而是独立的),这样我们就不⽤担⼼不同的测试⽤例之间会有数据上的影响了,保证所有的测试⽤例都使⽤相同的测试环境进⾏测试

实操:

独立测试事件类:

  1. 创建MyTest类,公开继承testing::Test
  2. 成员函数
    1. static void SetIpTestCase()
    2. static void TearDownTestCase()
    3. void SetUp() override
    4. void TearDown() override
  3. 成员变量(公用的)
    1. map

测试单元:
其中每一个单元测试中他们得到独立测试事件中的变量都是独立属于自己的

  1. TEST_F(MyTest,insert_test)
  2. TEST_F(MyTest,size_test)

主函数:

  1. 初始化单元测试 InitGoogleTest
  2. RUN_ALL_TESTS

具体代码:

#include <iostream>
#include <gtest/gtest.h>
#include <unordered_map>class MyTest : public testing::Test {public:static void SetUpTestCase() {std::cout << "所有单元测试前执行,初始化总环境!\n";//假设我有一个全局的测试数据容器,在这里插入公共的测试数据}void SetUp() override {//在这里插入每个单元测试所需的独立的测试数据std::cout << "单元测试初始化!!\n";_mymap.insert(std::make_pair("hello", "你好"));_mymap.insert(std::make_pair("bye", "再见"));}void TearDown() override {//在这里清理每个单元测试自己插入的数据_mymap.clear();std::cout << "单元测试清理!!\n";}static void TearDownTestCase() { //清理公共的测试数据std::cout << "所有单元测试完毕执行,清理总环境!\n";}public:std::unordered_map<std::string, std::string> _mymap;
};TEST_F(MyTest, insert_test) {_mymap.insert(std::make_pair("leihou", "你好"));ASSERT_EQ(_mymap.size(), 3);}
TEST_F(MyTest, size_test) {ASSERT_EQ(_mymap.size(), 2);
}int main(int argc, char *argv[])
{testing::InitGoogleTest(&argc, argv);RUN_ALL_TESTS();return 0;
}

在这里插入图片描述

通过对单元测试用例中的共用成员map操作,发现在第一个TEST_F中map内元素个数是3,而第二个TEST_F中map元素个数是2,都没报错,所以每个单元是独立的!


本章完。预知后事如何,暂听下回分解。

如果有任何问题欢迎讨论哈!

如果觉得这篇文章对你有所帮助的话点点赞吧!

持续更新大量C++细致内容,早关注不迷路。

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

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

相关文章

《机器学习》——贝叶斯算法

贝叶斯简介 贝叶斯公式&#xff0c;又称贝叶斯定理、贝叶斯法则&#xff0c;最初是用来描述两个事件的条件概率间的关系的公式&#xff0c;后来被人们发现具有很深刻的实际意义和应用价值。该公式的实际内涵是&#xff0c;支持某项属性的事件发生得愈多&#xff0c;则该属性成…

优先级队列(算法十四)

简介 优先级队列其实就是堆 默认大根堆 小根堆&#xff1a;greater<T> std::priority_queue<int, std::vector<int>, std::greater<int>> pq; priority_queue 没有迭代器&#xff0c; 不能for&#xff08;auto e:pq); 不改变原来pq&#xff0c;查…

【day5】Redis持久化之AOF + Redis事务_锁机制

AOF是什么 以日志的形式来记录每个写操作(增量保存)&#xff0c;将 Redis 执行过的所有写指令记录下来(比 如 set/del 操作会记录, 读操作 get 不记录 只许追加文件但不可以改写文件 redis 启动之初会读取该文件重新构建数据 redis 重启的话就根据日志文件的内容将写指令从前到…

C#补充----反射,特性,迭代器,特殊语法,值类型运用类型。

1.反射。 《1》获取类的方式 《2》反射的应用 <1>获取类型的所有公共成员 <2>获取构造函数 <3>获取类型的 公共成员变量 <4>获取类型的 公共方法 <5>.获取类型的 属性 <6>.公共接口&#xff0c;公共枚举&#xff0c;公共事件

MyBatis——XML映射文件

在MyBatis中&#xff0c;既可以通过注解的方式配置SQL语句&#xff0c;也可以通过XML映射文件的方式配置SQL语句。对于简单的SQL语句建议直接通过注解的方式配置SQL语句&#xff1a; Delete("delete from user where id#{id}") Integer deleteById(Integer id);但是…

git使用-小白入门2

git使用-小白入门2 分支git branch——显示分支git checkout -b——创建&#xff0c;切换分支git merge——合并分支git log --graph——以图标形式查看分支 推送至远程仓库 分支 在进行多个并行作业时&#xff0c;我们会用到分支。在这类并行开发的过程中&#xff0c;往往同时…

OpenAI Whisper:语音识别技术的革新者—深入架构与参数

当下语音识别技术正以前所未有的速度发展&#xff0c;极大地推动了人机交互的便利性和效率。OpenAI的Whisper系统无疑是这一领域的佼佼者&#xff0c;它凭借其卓越的性能、广泛的适用性和创新的技术架构&#xff0c;正在重新定义语音转文本技术的规则。今天我们一起了解一下Whi…

TiDB常见操作指南:从入门到进阶

TiDB常见操作指南&#xff1a;从入门到进阶 TiDB作为一个分布式数据库&#xff0c;提供了丰富的操作接口和功能。无论是基本的数据库管理&#xff0c;还是更为复杂的分布式事务处理&#xff0c;TiDB都能灵活应对。在这篇文章中&#xff0c;我们将总结几种TiDB常见操作&#xf…

NVIDIA CUDA Linux 官方安装指南

本文翻译自&#xff1a;https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#post-installation-actions NVIDIA CUDALinux安装指南 CUDA工具包的Linux安装说明。 文章目录 1.导言1.1.系统要求1.2.操作系统支持政策1.3.主机编译器支持政策1.3.1.支持的C方言…

rtthread学习笔记系列(4/5/6/7/15/16)

文章目录 4. 杂项4.1 检查是否否是2的幂 5. 预编译命令void类型和rt_noreturn类型的区别 6.map文件分析7.汇编.s文件7.1 汇编指令7.1.1 BX7.1.2 LR链接寄存器7.1.4 []的作用7.1.4 简单的指令 7.2 MSR7.3 PRIMASK寄存器7.4.中断启用禁用7.3 HardFault_Handler 15 ARM指针寄存器1…

一个使用 Golang 编写的新一代网络爬虫框架,支持JS动态内容爬取

大家好&#xff0c;今天给大家分享一个由ProjectDiscovery组织开发的开源“下一代爬虫框架”Katana&#xff0c;旨在提供高效、灵活且功能丰富的网络爬取体验&#xff0c;适用于各种自动化管道和数据收集任务。 项目介绍 Katana 是 ProjectDiscovery 精心打造的命令行界面&…

【Redis】初识Redis

目录 Redis简介 Redis在内存中存储数据 Redis数据库中的应用 Redis缓存中的应用 Redis消息中间件 尾言 Redis简介 如下是Redis官网中&#xff0c;对Redis的一段描述 在这段描述中&#xff0c;我们提取如下关键要点&#xff1a; Redis主要用于在内存中存储数据Redis可…

IDEA的Git界面(ALT+9)log选项不显示问题小记

IDEA的Git界面ALT9 log选项不显示问题 当前问题idea中log界面什么都不显示其他选项界面正常通过命令查询git日志正常 预期效果解决办法1. 检查 IDEA 的 Git 设置2. 刷新 Git Log (什么都没有大概率是刷新不了)3. 检查分支和日志是否存在4. 清理 IDEA 缓存 (我用这个成功解决)✅…

赤店商城系统点餐小程序多门店分销APP共享股东h5源码saas账号独立版全插件全开源

代码介绍 后端编程语言采用&#xff1a;PHP yii2.0框架 前端代码采用&#xff1a;UNIAPP框架环境要求 推荐选择服务器配置&#xff1a;2核4G内存3M带宽 linux操作系统 控制面板&#xff1a;宝塔面板 运行环境&#xff1a;PHP7.2MYSQL5.7 赤店商城系统是一款集点餐小程序、多门…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>优美的排列

题目&#xff1a; 解析&#xff1a; 部分决策树&#xff1a; 代码设计&#xff1a; 代码&#xff1a; private int count;private boolean[] check;public int countArrangement(int n) {check new boolean[n1];dfs(n,1);return count;} private void dfs(int n, int pos){…

【C++图论 拓扑排序】2392. 给定条件下构造矩阵|1960

本文涉及知识点 C图论 拓扑排序 LeetCode2392. 给定条件下构造矩阵 给你一个 正 整数 k &#xff0c;同时给你&#xff1a; 一个大小为 n 的二维整数数组 rowConditions &#xff0c;其中 rowConditions[i] [abovei, belowi] 和 一个大小为 m 的二维整数数组 colConditions…

Anaconda安装(2024最新版)

安装新的anaconda需要卸载干净上一个版本的anaconda&#xff0c;不然可能会在新版本安装过程或者后续使用过程中出错&#xff0c;完全卸载干净anaconda的方法&#xff0c;可以参考我的博客&#xff01; 第一步&#xff1a;下载anaconda安装包 官网&#xff1a;Anaconda | The O…

SSE部署后无法连接问题解决

1. 问题现象 通过域名访问 https://api-uat.sfxs.com/sse/subscribe?tokenBearer%20eyJUxMiJ9.eyJhY2NvdW50IjoiYWRtaWZ0NvZGUiOiIwMDEiLCJyb2xidXNlcm5hbWUiOiLotoXnuqfnrqHnkIblkZgifQ.tlz9N61Y4 一直无法正常连接 2. 问题解决 nginx.conf进行配置 server {location /ss…

【优选算法篇】:分而治之--揭秘分治算法的魅力与实战应用

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;优选算法篇–CSDN博客 文章目录 一.什么是分治算法1.分治算法的基本概念2.分治算法的三个步…

Unreal Engine 5 C++ Advanced Action RPG 八章笔记

第八章 Boss Enemy 2-Set Up Boss Character 创建Boss敌人流程 起始的数据UI战斗能力行为树 这集新建Boss敌人的蓝图与动画蓝图和混合空间,看看就行巨人在关卡中,它的影子被打破,更改当前项目中的使用的阴影贴图就可以解决 从虚拟阴影贴图更改为阴影贴图即可 3-Giant Start…