【机器学习】libsvm 简单使用示例(C++)

news2024/9/22 7:34:14

libsvm简单使用demo

一、libsvm使用说明

d5da350d20d9cd9eb219682f085613d6.png

二、svm.h源码

#ifndef _LIBSVM_H //如果没有定义 _LIBSVM_H 宏
#define _LIBSVM_H //则定义 _LIBSVM_H 宏,用于防止重复包含


#define LIBSVM_VERSION 317 //定义一个宏,表示 libsvm 的版本号


#ifdef __cplusplus //如果是 C++ 编译器
extern "C" { //则使用 C 语言的链接方式
#endif


extern int libsvm_version; //声明一个外部变量,表示 libsvm 的版本号


struct svm_node //定义一个结构体,表示一个特征节点
{
  int index; //特征的索引
  double value; //特征的值
};


struct svm_problem //定义一个结构体,表示一个 SVM 问题
{
  int l; //训练集的行数
  double *y; //训练集的标签向量
  struct svm_node **x; //训练集的特征矩阵
};


enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR };  /* svm_type */ //定义一个枚举类型,表示 SVM 的类型
enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */ //定义一个枚举类型,表示核函数的类型


struct svm_parameter //定义一个结构体,表示 SVM 的参数
{
  int svm_type; //SVM 的类型
  int kernel_type; //核函数的类型
  int degree;  /* for poly */ //多项式核函数的次数
  double gamma;  /* for poly/rbf/sigmoid */ //核函数的系数
  double coef0;  /* for poly/sigmoid */ //核函数的常数项


  /* these are for training only */ //以下是只用于训练的参数
  double cache_size; /* in MB */ //内核缓存的大小(以 MB 为单位)
  double eps;  /* stopping criteria */ //停止准则的容差
  double C;  /* for C_SVC, EPSILON_SVR and NU_SVR */ //C-SVM 分类器或回归器的惩罚系数
  int nr_weight;    /* for C_SVC */ //不同类别的权重的个数
  int *weight_label;  /* for C_SVC */ //不同类别的权重的标签
  double* weight;    /* for C_SVC */ //不同类别的权重的值
  double nu;  /* for NU_SVC, ONE_CLASS, and NU_SVR */ //nu-SVM 分类器或回归器的参数
  double p;  /* for EPSILON_SVR */ //epsilon-SVR 回归器的损失函数的参数
  int shrinking;  /* use the shrinking heuristics */ //是否使用启发式收缩
  int probability; /* do probability estimates */ //是否计算概率估计
};


//
// svm_model
// 
struct svm_model //定义一个结构体,表示 SVM 的模型
{
  struct svm_parameter param;  /* parameter */ //SVM 的参数
  int nr_class;    /* number of classes, = 2 in regression/one class svm */ //类别的个数,回归或单类 SVM 为 2
  int l;      /* total #SV */ //支持向量的总数
  struct svm_node **SV;    /* SVs (SV[l]) */ //支持向量的矩阵
  double **sv_coef;  /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ //支持向量在决策函数中的系数
  double *rho;    /* constants in decision functions (rho[k*(k-1)/2]) */ //决策函数中的常数
  double *probA;    /* pariwise probability information */ //成对概率信息
  double *probB;
  int *sv_indices;        /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */ //支持向量在训练集中的索引


  /* for classification only */ //以下是只用于分类的信息


  int *label;    /* label of each class (label[k]) */ //每个类别的标签
  int *nSV;    /* number of SVs for each class (nSV[k]) */ //每个类别的支持向量的个数
        /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */
  /* XXX */
  int free_sv;    /* 1 if svm_model is created by svm_load_model*/
        /* 0 if svm_model is created by svm_train */ //表示 svm_model 是由 svm_load_model 还是 svm_train 创建的
};


struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); //声明一个函数,用于训练 SVM 模型,参数为 SVM 问题和 SVM 参数,返回值为 SVM 模型的指针
void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target); //声明一个函数,用于进行交叉验证,参数为 SVM 问题、SVM 参数、交叉验证的折数和目标向量,无返回值


int svm_save_model(const char *model_file_name, const struct svm_model *model); //声明一个函数,用于保存 SVM 模型到文件,参数为文件名和 SVM 模型的指针,返回值为 0 表示成功,-1 表示失败
struct svm_model *svm_load_model(const char *model_file_name); //声明一个函数,用于从文件加载 SVM 模型,参数为文件名,返回值为 SVM 模型的指针,如果失败则为 NULL


int svm_get_svm_type(const struct svm_model *model); //声明一个函数,用于获取 SVM 的类型,参数为 SVM 模型的指针,返回值为枚举类型的值
int svm_get_nr_class(const struct svm_model *model); //声明一个函数,用于获取类别的个数,参数为 SVM 模型的指针,返回值为整数
void svm_get_labels(const struct svm_model *model, int *label); //声明一个函数,用于获取每个类别的标签,参数为 SVM 模型的指针和标签向量,无返回值
void svm_get_sv_indices(const struct svm_model *model, int *sv_indices); //声明一个函数,用于获取支持向量在训练集中的索引,参数为 SVM 模型的指针和索引向量,无返回值
int svm_get_nr_sv(const struct svm_model *model); //声明一个函数,用于获取支持向量的个数,参数为 SVM 模型的指针,返回值为整数
double svm_get_svr_probability(const struct svm_model *model); //声明一个函数,用于获取 SVR 的概率估计,参数为 SVM 模型的指针,返回值为浮点数,如果失败则为 0


double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values); //声明一个函数,用于预测一个样本的决策值,参数为 SVM 模型的指针、样本的特征向量和决策值向量,返回值为预测的标签
double svm_predict(const struct svm_model *model, const struct svm_node *x); //声明一个函数,用于预测一个样本的标签,参数为 SVM 模型的指针和样本的特征向量,返回值为预测的标签
double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates); //声明一个函数,用于预测一个样本的概率估计,参数为 SVM 模型的指针、样本的特征向量和概率估计向量,返回值为预测的标签


void svm_free_model_content(struct svm_model *model_ptr); //声明一个函数,用于释放 SVM 模型的内容,参数为 SVM 模型的指针,无返回值
void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr); //声明一个函数,用于释放并销毁 SVM 模型,参数为 SVM 模型的指针的指针,无返回值
void svm_destroy_param(struct svm_parameter *param); //声明一个函数,用于销毁 SVM 参数,参数为 SVM 参数的指针,无返回值


const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param); //声明一个函数,用于检查 SVM 参数是否合法,参数为 SVM 问题和 SVM 参数的指针,返回值为一个字符串,如果为 NULL,则表示参数合法,否则表示参数有误


int svm_check_probability_model(const struct svm_model *model); //声明一个函数,用于检查 SVM 模型是否支持概率估计,参数为 SVM 模型的指针,返回值为一个整数,如果为 0,则表示不支持,否则表示支持


void svm_set_print_string_function(void (*print_func)(const char *)); //声明一个函数,用于设置 libsvm 的输出函数,参数为一个函数指针,该函数接受一个字符串作为参数,无返回值


#ifdef __cplusplus //如果是 C++ 编译器
}
#endif //则结束 C 语言的链接方式


#endif /* _LIBSVM_H */ //结束防止重复包含的条件

三、示例demo

43702fe00a16f12074a87557e582e46a.png

#include "svm.h" //引入 libsvm 的头文件
#include <ctype.h> //引入字符处理的头文件
#include <stdlib.h> //引入标准库的头文件
#include <vector> //引入向量容器的头文件
#include <iostream> //引入输入输出流的头文件
using namespace std; //使用标准命名空间


#define Malloc(type,n) (type *)malloc((n)*sizeof(type)) //定义一个宏,用于分配内存


struct svm_parameter param;    // 由 parse_command_line 函数设置,用于存储 SVM 的参数
struct svm_problem prob;    // 由 read_problem 函数设置,用于存储训练集的特征和标签
struct svm_model *model; //用于存储训练后的 SVM 模型
struct svm_node *x_space; //用于存储训练集的特征向量


vector<int> generateLabels(int labelsSize) //定义一个函数,用于生成标签向量
{
  std::vector<int> labels; //创建一个 int 类型的向量
  for (int i=0; i<labelsSize; ++i) //循环 labelsSize 次
  {
    labels.push_back(i%2+1); //向向量中添加元素,值为 i 除以 2 的余数加 1
  }
  return labels; //返回向量
}


vector<vector<double> > generateData(int problemSize, int featureNum) //定义一个函数,用于生成特征数据
{
  std::vector<std::vector<double> > data; //创建一个 double 类型的二维向量
  for (int i=0; i<problemSize; ++i) //循环 problemSize 次
  {
    std::vector<double> featureSet; //创建一个 double 类型的向量,用于存储一行特征
    for (int j=0; j<featureNum; ++j) //循环 featureNum 次
    {
      cout<<"feature pushed"<<endl; //输出提示信息
      featureSet.push_back(j); //向向量中添加元素,值为 j
    }
    data.push_back(featureSet); //将向量添加到二维向量中
  }
  return data; //返回二维向量
}


int main() //定义主函数
{
  //here I will create a small artificial problem just for illustration
  int sizeOfProblem = 30; //定义一个变量,表示训练集的行数
  int elements = 10; //定义一个变量,表示每行特征的个数


  vector<vector<double> > data = generateData(sizeOfProblem,elements); //调用 generateData 函数,生成特征数据
  vector<int> labels = generateLabels(sizeOfProblem); //调用 generateLabels 函数,生成标签数据


  cout<<"data size = "<<data.size()<<endl; //输出特征数据的大小
  cout<<"labels size = "<<labels.size()<<endl; //输出标签数据的大小
  //initialize the size of the problem with just an int  
  prob.l = sizeOfProblem; //将 prob 结构体的 l 成员赋值为训练集的行数
  //here we need to give some memory to our structures
  // @param prob.l = number of labels
  // @param elements = number of features for each label
  prob.y = Malloc(double,prob.l); //为 prob 结构体的 y 成员分配内存,用于存储标签向量
  prob.x = Malloc(struct svm_node *, prob.l); //为 prob 结构体的 x 成员分配内存,用于存储特征向量的指针
  x_space = Malloc(struct svm_node, (elements+1) * prob.l); //为 x_space 分配内存,用于存储特征向量的索引和值


  //here we are going to initialize it all a bit


  
  //initialize the different lables with an array of labels
  for (int i=0; i < prob.l; ++i) //循环 prob.l 次
  {
    prob.y[i] = labels[i]; //将 prob 结构体的 y 成员的第 i 个元素赋值为标签向量的第 i 个元素
    cout<<"prob.y["<<i<<"] = "<<prob.y[i]<<endl; //输出赋值结果
  }
  //initialize the svm_node vector with input data array as follows:
  int j=0; //定义一个变量,用于遍历 x_space
  for (int i=0;i < prob.l; ++i) //循环 prob.l 次
  {
    //set i-th element of prob.x to the address of x_space[j]. 
    //elements from x_space[j] to x_space[j+data[i].size] get filled right after next line
    prob.x[i] = &x_space[j]; //将 prob 结构体的 x 成员的第 i 个元素赋值为 x_space 的第 j 个元素的地址
    for (int k=0; k<data[i].size(); ++k, ++j) //循环 data[i].size() 次,同时增加 j 的值
    {
      x_space[j].index=k+1; //将 x_space 的第 j 个元素的 index 成员赋值为 k+1,表示特征的索引
      x_space[j].value=data[i][k]; //将 x_space 的第 j 个元素的 value 成员赋值为 data[i][k],表示特征的值
      cout<<"x_space["<<j<<"].index = "<<x_space[j].index<<endl; //输出赋值结果
      cout<<"x_space["<<j<<"].value = "<<x_space[j].value<<endl; //输出赋值结果
    }
    x_space[j].index=-1;//state the end of data vector
    x_space[j].value=0; //将 x_space 的第 j 个元素的 index 成员赋值为 -1,表示特征向量的结束,将 value 成员赋值为 0
    cout<<"x_space["<<j<<"].index = "<<x_space[j].index<<endl; //输出赋值结果
    cout<<"x_space["<<j<<"].value = "<<x_space[j].value<<endl; //输出赋值结果
    j++; //增加 j 的值


  }


  //ok, let's try to print it
  for (int i = 0; i < prob.l; ++i) //循环 prob.l 次
  {
    cout<<"line "<<i<<endl; //输出提示信息
    cout<<prob.y[i]<<"---"; //输出标签
    for (int k = 0; k < elements; ++k) //循环 elements 次
    {
      int index = (prob.x[i][k].index); //获取特征的索引
      double value = (prob.x[i][k].value); //获取特征的值
      cout<<index<<":"<<value<<" "; //输出索引和值
    }
    cout<<endl; //换行
  }
  cout<<"all ok"<<endl; //输出提示信息


  //set all default parameters for param struct
  param.svm_type = C_SVC; //将 param 结构体的 svm_type 成员赋值为 C_SVC,表示使用 C-SVM 分类器
  param.kernel_type = RBF; //将 param 结构体的 kernel_type 成员赋值为 RBF,表示使用径向基核函数
  param.degree = 3; //将 param 结构体的 degree 成员赋值为 3,表示多项式核函数的次数
  param.gamma = 0;  // 1/num_features //将 param 结构体的 gamma 成员赋值为 0,表示核函数的系数,如果为 0,则默认为 1/num_features
  param.coef0 = 0; //将 param 结构体的 coef0 成员赋值为 0,表示核函数的常数项
  param.nu = 0.5; //将 param 结构体的 nu 成员赋值为 0.5,表示 nu-SVM 分类器或回归器的参数
  param.cache_size = 100; //将 param 结构体的 cache_size 成员赋值为 100,表示内核缓存的大小(以 MB 为单位)
  param.C = 1; //将 param 结构体的 C 成员赋值为 1,表示 C-SVM 分类器或回归器的惩罚因子
  param.eps = 1e-3; //将 param 结构体的 eps 成员赋值为 1e-3,表示停止准则的容差
  param.p = 0.1; //将 param 结构体的 p 成员赋值为 0.1,表示 epsilon-SVR 回归器的损失函数的参数
  param.shrinking = 1; //将 param 结构体的 shrinking 成员赋值为 1,表示是否使用启发式收缩
  param.probability = 0; //将 param 结构体的 probability 成员赋值为 0,表示是否计算概率估计
  param.nr_weight = 0; //将 param 结构体的 nr_weight 成员赋值为 0,表示不同类别的权重的个数
  param.weight_label = NULL; //将 param 结构体的 weight_label 成员赋值为 NULL,表示不同类别的权重的标签
  param.weight = NULL; //将 param 结构体的 weight 成员赋值为 NULL,表示不同类别的权重的值


  //try to actually execute it
  model = svm_train(&prob, &param); //调用 svm_train 函数,用 prob 和 param 作为参数,训练 SVM 模型,并将结果赋值给 model
  return 0; //返回 0,表示程序正常结束
}

输出结果:

feature pushed(第1行)
……
feature pushed(第300行)
data size = 30
labels size = 30
prob.y[0] = 1
prob.y[1] = 2
prob.y[2] = 1
prob.y[3] = 2
prob.y[4] = 1
prob.y[5] = 2
prob.y[6] = 1
prob.y[7] = 2
prob.y[8] = 1
prob.y[9] = 2
prob.y[10] = 1
prob.y[11] = 2
prob.y[12] = 1
prob.y[13] = 2
prob.y[14] = 1
prob.y[15] = 2
prob.y[16] = 1
prob.y[17] = 2
prob.y[18] = 1
prob.y[19] = 2
prob.y[20] = 1
prob.y[21] = 2
prob.y[22] = 1
prob.y[23] = 2
prob.y[24] = 1
prob.y[25] = 2
prob.y[26] = 1
prob.y[27] = 2
prob.y[28] = 1
prob.y[29] = 2
x_space[0].index = 1(第1个数据)
x_space[0].value = 0
x_space[1].index = 2
x_space[1].value = 1
x_space[2].index = 3
x_space[2].value = 2
x_space[3].index = 4
x_space[3].value = 3
x_space[4].index = 5
x_space[4].value = 4
x_space[5].index = 6
x_space[5].value = 5
x_space[6].index = 7
x_space[6].value = 6
x_space[7].index = 8
x_space[7].value = 7
x_space[8].index = 9
x_space[8].value = 8
x_space[9].index = 10
x_space[9].value = 9
x_space[10].index = -1
x_space[10].value = 0
(第2个数据)
x_space[11].index = 1
x_space[11].value = 0
x_space[12].index = 2
x_space[12].value = 1
x_space[13].index = 3
x_space[13].value = 2
x_space[14].index = 4
x_space[14].value = 3
x_space[15].index = 5
x_space[15].value = 4
x_space[16].index = 6
x_space[16].value = 5
x_space[17].index = 7
x_space[17].value = 6
x_space[18].index = 8
x_space[18].value = 7
x_space[19].index = 9
x_space[19].value = 8
x_space[20].index = 10
x_space[20].value = 9
x_space[21].index = -1
x_space[21].value = 0
……
(第30个数据)
x_space[319].index = 1
x_space[319].value = 0
x_space[320].index = 2
x_space[320].value = 1
x_space[321].index = 3
x_space[321].value = 2
x_space[322].index = 4
x_space[322].value = 3
x_space[323].index = 5
x_space[323].value = 4
x_space[324].index = 6
x_space[324].value = 5
x_space[325].index = 7
x_space[325].value = 6
x_space[326].index = 8
x_space[326].value = 7
x_space[327].index = 9
x_space[327].value = 8
x_space[328].index = 10
x_space[328].value = 9
x_space[329].index = -1
x_space[329].value = 0
line 0
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 1
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 2
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 3
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 4
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 5
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 6
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 7
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 8
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 9
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 10
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 11
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 12
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 13
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 14
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 15
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 16
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 17
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 18
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 19
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 20
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 21
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 22
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 23
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 24
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 25
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 26
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 27
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 28
1---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
line 29
2---1:0 2:1 3:2 4:3 5:4 6:5 7:6 8:7 9:8 10:9
all ok
*
optimization finished, #iter = 15
nu = 1.000000
obj = -30.000000, rho = 0.000000
nSV = 30, nBSV = 30
Total nSV = 30

参考网址

https://github.com/cjlin1/libsvm

https://github.com/niosus/SVM_example

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

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

相关文章

uniapp之屏幕右侧出现滚动条去掉、隐藏、删除【好用!】

目录 问题解决大佬地址最后 问题 解决 在最外层view上加上class“content”;输入以下样式。注意&#xff1a;两个都必须存在在生效。 .content {/* 跟屏幕高度一样高,不管view中有没有内容,都撑开屏幕高的高度 */height: 100vh; overflow: auto; } .content::-webkit-scrollb…

计算机网络考研辨析(后续整理入笔记)

文章目录 体系结构物理层速率辨析交换方式辨析编码调制辨析 链路层链路层功能介质访问控制&#xff08;MAC&#xff09;信道划分控制之——CDMA随机访问控制轮询访问控制 扩展以太网交换机 网络层网络层功能IPv4协议IP地址IP数据报分析ICMP 网络拓扑与转发分析&#xff08;重点…

软件设计师——计算机网络(三)

&#x1f4d1;前言 本文主要是【计算机网络】——软件设计师——计算机网络的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1…

Mac安装Typora实现markdown自由

一、什么是markdown Markdown 是一种轻量级标记语言&#xff0c;创始人为约翰格鲁伯&#xff08;John Gruber&#xff09;。 它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的 XHTML&#xff08;或者HTML&#xff09;文档。这种语言吸收了很多在电子邮…

【AI工具】GitHub Copilot IDEA安装与使用

GitHub Copilot是一款AI编程助手&#xff0c;它可以帮助开发者编写代码&#xff0c;提供代码建议和自动完成功能。以下是GitHub Copilot在IDEA中的安装和使用步骤&#xff1a; 安装步骤&#xff1a; 打开IDEA&#xff0c;点击File -> Settings -> Plugins。在搜索框中输…

棋牌的电脑计时计费管理系统教程,棋牌灯控管理软件操作教程

一、前言 有的棋牌室在计时的时候&#xff0c;需要使用灯控管理&#xff0c;在开始计时的时候打开灯&#xff0c;在结账后关闭灯&#xff0c;也有的不需要用灯控&#xff0c;只用来计时。 下面以 佳易王棋牌计时计费管理系统软件为例说明&#xff1a; 软件试用版下载或技术支…

Selenium安装WebDriver:ChromeDriver与谷歌浏览器版本快速匹配_最新版120

最近在使用通过selenium操作Chrome浏览器时&#xff0c;安装中遇到了Chrome版本与浏览器驱动不匹配的的问题&#xff0c;在此记录安装下过程&#xff0c;如何快速找到与谷歌浏览器相匹配的ChromeDriver驱动版本。 1. 确定Chrome版本 我们首先确定自己的Chrome版本 Chrome设置…

NE555汽车防盗报警电路图

实用汽车防盗报警电路如图所示。它主要由防盗部分和报警两大部分电路组成。防盗电路&#xff1a;当汽车主人离开汽车时&#xff0c;将防盗开关S置于“B”位置&#xff0c;使汽车进入防盗状态。当有窃贼进入驾驶室企图发动汽车将其盗走时&#xff0c;只要拧动点火开关&#xff0…

python+requests+pytest 接口自动化实现

最近工作之余拿公司的项目写了一个接口测试框架&#xff0c;功能还不是很完善&#xff0c;算是抛砖引玉了&#xff0c;欢迎各位来吐槽。 主要思路&#xff1a; ①对 requests 进行二次封装&#xff0c;做到定制化效果 ②使用 excel 存放接口请求数据&#xff0c;作为数据驱动 ③…

PhpStorm下载、安装、配置教程

前面的文章中&#xff0c;都是把.php文件放在WampServer的www目录下&#xff0c;通过浏览器访问运行。这篇文章就简单介绍一下PhpStorm这个php集成开发工具的使用。 目录 下载PhpStorm 安装PhpStorm 配置PhpStorm 修改个性化设置 修改字符编码 配置php的安装路径 使用Ph…

MySQL 常用数据类型总结

面试&#xff1a; 为什么建表时,加not null default ‘’ / default 0 答:不想让表中出现null值. 为什么不想要的null的值 答:&#xff08;1&#xff09;不好比较,null是一种类型,比较时,只能用专门的is null 和 is not null来比较. 碰到运算符,一律返回null &#xff08…

【Spring】06 生命周期之销毁回调

文章目录 1. 回调是什么2. 销毁回调2.1 实现 DisposableBean 接口2.2 配置 destroy-method 3. 执行顺序4. 应用场景总结 在 Spring 框架中&#xff0c;生命周期回调&#xff08;Lifecycle Callbacks&#xff09;是一种强大的机制&#xff0c;它允许我们在 Spring 容器中的 Bean…

Mybatis-Spring整合原理:MapperFactoryBean和MapperScannerConfigurer的区别及源码剖析

文章目录 引言MapperFactoryBean的用法和优缺点MapperScannerConfigurer的用法和优缺点MapperFactoryBean源码分析MapperScannerConfigurer源码分析Spring容器初始化流程回顾核心方法&#xff1a;postProcessBeanDefinitionRegistryBeanDefinitionRegistryPostProcessor和BeanF…

杰理-音箱-flash配置

杰理-音箱-flash配置 注意配置io&#xff0c;双线或者4线的硬件连接方式&#xff0c;否则无法烧录UI资源

STM32与Freertos入门(七)信号量

1、简介 FreeRTOS提供了二值信号&#xff08;Binary Semaphore&#xff09;作为一种同步机制&#xff0c;用于在任务之间进行简单的通信和同步操作。二值信号是一种特殊类型的信号量&#xff0c;只能有两种状态&#xff1a;0&#xff08;未触发&#xff09;和1&#xff08;已触…

PAT 乙级 1019 数字黑洞

解法思路,我用c语言和python 做了这道题&#xff0c;这里面有一个小坑就是没说一定是4位整数&#xff0c;有可能是3位&#xff0c;2,1&#xff0c;位&#xff0c;用python排序时候需要注意&#xff0c;我c语言用的hash反而无所谓。。代码如下&#xff1a; c语言代码: #includ…

CTFHub | 反射型

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

腾讯云服务器优惠活动大全页面_全站搜优惠合集

腾讯云推出优惠全站搜页面 https://curl.qcloud.com/PPrF9NFe 在这个页面可以一键查询所需云服务器、轻量应用服务器、数据库、存储、CDN、网络、安全、大数据等云产品优惠活动大全&#xff0c;活动打开如下图&#xff1a; 腾讯云优惠全站搜 腾讯云优惠全站搜页面 txybk.com/go…

STP笔记总结

STP --- 生成树协议 STP&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09;是根据 IEEE802.1D标准建立的&#xff0c;用于在局域网中消除数据链路层环路的协议。运行STP协议的设备通过彼此交互信息发现网络中的环路&#xff0c;并有选择地对某些端口进行阻…

MyBatis原理解读

我们项目中多用MyBatis进行数据库的读写,开源的MyBatis-Plus框架对其进行了增强,使用上更加简单,我们之前的很多项目也是直接用的MyBatis-Plus。 数据库操作的时候,简单的单表读写,我们可以直接在方法里链式组装SQL,复杂的SQL或涉及多表联合join的,需要在xml手写SQL语句…