c语言的qsort函数理解与使用
介绍:qsort 函数是 C 标准库中用于排序的快速排序算法函数。它的用法非常灵活,可以对任意类型的元素进行排序,只要提供了比较函数即可。
qsort 函数原型及参数解释:
void qsort (
void* base, //指向要排序的数组的首元素的指针
size_t num, //待排序数组中元素的个数
size_t size, //待排序数组中每个元素的大小(以字节为单位)
int (*compare)(const void*,const void*) //比较函数的指针,用于确定元素之间的排序
);
注意:
使用qsort函数时,需要根据实际情况编写一个合适的比较函数来确定排序规则。
比较函数可以根据元素的类型和排序需求进行自定义。
比较函数的原型如下:
int compare(const void *a, const void *b);
比较函数需要返回一个整数值,表示两个元素之间的关系:
如果返回值小于0,则表示a应该排在b之前。
如果返回值等于0,则表示a和b相等,它们的相对顺序不变。
如果返回值大于0,则表示a应该排在b之后。
对于一个数组或是任意需要进行排序的内容进行排序时可以理解如下:
// qsort中自定义比较函数compare返回值 > 0表示对需要排序的内容进行升序排序(小->大)
// qsort中自定义比较函数compare返回值 < 0表示对需要排序的内容进行降序排序(大->小)
实例:
// qsort排序举例:升序排序(小->大)
// 自定义比较函数返回值 > 0表示对需要排序的内容进行升序排序// qsort 函数是 C 标准库中用于排序的快速排序算法函数。
// 它的用法非常灵活,可以对任意类型的元素进行排序,只要提供了比较函数即可。#include <stdio.h>
#include <stdlib.h>// 比较函数的形式为:
// int cmp(const void *a, const void *b);
// 其中,cmp 函数用于比较 a 和 b 两个指针所指向的元素的大小关系,
// 如果 a 指向的元素小于 b 指向的元素,则返回负数;
// 如果 a 指向的元素大于 b 指向的元素,则返回正数;
// 如果 a 指向的元素等于 b 指向的元素,则返回 0。
// 下面我们来看一个最简单的实例代码,用于对整数数组进行排序:
int compare(const void *a, const void *b)
{printf("%d - %d = %d, ", *(int *)a, *(int *)b, (*(int *)a - *(int *)b));return (*(int*)a - *(int*)b);
}int main()
{int arr0[] = {2, 1};int len = sizeof(arr0) / sizeof(int);// 这段代码的核心部分就是使用 qsort 函数对整数数组进行排序,排序时需要传递一个比较函数 cmp。// cmp 函数的实现非常简单,就是计算 a 和 b 之间的差值。最后,我们依次输出排序后的整数数组。// 需要注意的是,在使用 qsort 函数时,我们需要传递以下参数:// 1. 待排序的数组的首地址。// 2. 数组中元素的个数。// 3. 每个元素的大小(以字节为单位)。// 4. 比较函数的地址(即函数指针)。// 这里我们传递的数组是 int 类型的数组,每个元素占据 4 个字节;// 比较函数 cmp 的地址可以直接传递函数名,也可以使用 & 运算符取地址。// 这就是 qsort 函数的基本用法。// 需要注意的是,cmp 函数要保证正确性和稳定性才能得到正确的排序结果,同时在实际使用时,也需要根据具体情况进行参数传递和处理。printf("arr0 升序排序过程:\n");// compare 返回值 > 0表示对数组arr1进行降序排序qsort(arr0, len, sizeof(int), compare);printf("\narr0 after sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr0[i]);}printf("\n");int arr1[] = {3, 2, 1, 5, -2, 9};int len1 = sizeof(arr1) / sizeof(int);printf("\narr1 升序排序过程:\n");// compare 返回值 > 0表示对数组arr1进行降序排序qsort(arr1, len1, sizeof(int), compare);printf("\narr1 after sort:\n");for (int i = 0; i < len1; i++) {printf("%d ", arr1[i]);}printf("\n");return 0;
}
// qsort排序举例:降序排序(大->小)
#include <stdio.h>
#include <stdlib.h>int cmp0(const void *a, const void *b)
{printf("%d - %d = %d, ", *(int *)a, *(int *)b, (*(int *)a - *(int *)b));return -(*(int*)a - *(int*)b);
}int cmp1(const void *a, const void *b)
{printf("%d - %d = %d, ", *(int *)b, *(int *)a, (*(int *)b - *(int*)a));return (*(int *)b - *(int*)a);
}int main()
{int arr[] = {5, 4, 2, 5, 3, 1};int len = sizeof(arr) / sizeof(int);printf("升序排序过程:\n");// cmp1返回值 < 0表示对数组arr1进行降序排序qsort(arr, len, sizeof(int), cmp0);printf("\nafter sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr[i]);}printf("\n");// cmp1返回值 < 0表示对数组arr1进行降序排序int arr1[] = {3, 2, 1, 5, -2, 9};printf("降序排序过程:\n");qsort(arr1, len, sizeof(int), cmp1);printf("\nafter sort:\n");for (int i = 0; i < len; i++) {printf("%d ", arr1[i]);}printf("\n");return 0;
}
// 对浮点数进行排序
#include <stdio.h>
#include <stdlib.h>// 对浮点数进行升序排序
int cmpFloat2Ascending(const void *a, const void *b)
{return *(float *)a - *(float *)b;
}// 对浮点数进行降序排序
int cmpFloat2Descending(const void *a, const void *b)
{return -(*(float *)a - *(float *)b);
}int main()
{float arr0[] = { -0.52, 1.7, 20.5, 9.9, 10.22 };int num0 = sizeof(arr0) / sizeof(int);printf("升序排序过程:\n");// cmp1返回值 < 0表示对数组arr1进行降序排序qsort(arr0, num0, sizeof(float), cmpFloat2Ascending);printf("\nafter sort:\n");for (int i = 0; i < num0; i++) {printf("%.2f ", arr0[i]);}printf("\n");// cmp1返回值 < 0表示对数组arr1进行降序排序float arr1[] = {3.3, 5.2, 1.1, 0.5, -1.2, 9.9};int num1 = sizeof(arr0) / sizeof(float);printf("降序排序过程:\n");qsort(arr1, num1, sizeof(float), cmpFloat2Descending);printf("\nafter sort:\n");for (int i = 0; i < num1; i++) {printf("%.2f ", arr1[i]);}printf("\n");return 0;
}
// qsort 函数对结构体类型的数据进行升序和降序排序:
// 这个程序定义了一个 Student 结构体类型,包含了学生的姓名、年龄和考试成绩三个成员变量。
// 在比较函数中,我们先比较考试成绩的大小,如果不同则返回差值;
// 如果考试成绩相同,则比较年龄的大小,如果不同则返回差值;
// 如果年龄也相同,则比较姓名的大小,从而实现了升序和降序排序。
// 在 main 函数中,我们首先定义了一个 Student 类型的数组,用于测试排序结果。
// 然后先调用 qsort 函数实现升序排序,并输出排序后的结果;
// 接着再调用 qsort 函数实现降序排序,并输出排序后的结果。
// 需要注意的是,在实际使用 qsort 函数时,需要根据具体情况进行参数传递和处理,
// 特别是在程序中使用了自定义结构体类型时,需要编写相应的比较函数来实现排序。
// 同时,也需要特别注意比较函数的实现方式,确保能够正确地比较结构体类型的各个成员变量。#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;int score;
} Student;// 升序
int cmpAsc(const void *a, const void *b)
{Student *sa = (Student *)a;Student *sb = (Student *)b;if (sa->score != sb->score) {return sa->score - sb->score;} else if (sa->age != sb->age) {return sa->age - sb->age;} else {return strcmp(sa->name, sb->name);}
}// 降序
int cmpDesc(const void *a, const void *b)
{Student *sa = (Student *)a;Student *sb = (Student *)b;if (sa->score != sb->score) {return -(sa->score - sb->score);} else if (sa->age != sb->age) {return -(sa->age - sb->age);} else {return -strcmp(sa->name, sb->name);}
}int main()
{Student students[] = {{"Alice", 18, 80},{"Bob", 20, 70},{"Charlie", 19, 90},{"David", 18, 80},{"Ella", 20, 85}};int n = sizeof(students) / sizeof(students[0]);// 升序qsort(students, n, sizeof(Student), cmpAsc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\t Score: %d\n", students[i].name, students[i].age, students[i].score);}printf("\n");// 降序排序qsort(students, n, sizeof(Student), cmpDesc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\t Score: %d\n", students[i].name, students[i].age, students[i].score);}return 0;
}
// 实现一个自定义的模拟qsort函数
// 在这个程序中,我们首先定义了一个 Person 结构体类型,包含名称和年龄两个成员变量。
// 在比较函数中,我们首先比较名称的大小,如果不同则返回名称的差值;
// 如果名称相同,则比较年龄的大小,从而实现了升序和降序排序。
// 在 bubble_sort 函数中,我们使用冒泡排序的逻辑来实现元素的排序,传入的对象是 void 指针,
// 因此我们需要将其强制转换为 char 指针,然后利用 memcpy 函数以元素的大小 width 为单位进行移动。
// 每次比较都使用传入的函数指针 cmp 来比较元素的大小,如果需要交换则使用 memcpy 函数来实现交换。
// 在 main 函数中,我们首先定义了一个 Person 类型的数组,包含了五个元素。
// 我们先对数组进行升序排序打印输出,然后再进行降序排序打印输出。
// 需要注意的是,在输出时使用了结构体的成员变量 name 和 age,分别代表了名称和年龄
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;
} Person;int cmp_asc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pa->name, pb->name);} else {return pa->age - pb->age;}
}int cmp_desc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pb->name, pa->name);} else {return pb->age - pa->age;}
}void bubble_sort0(void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
{char *array = (char *)base;for (int i = 0; i < nel - 1; i++) {for (int j = i + 1; j < nel; j++) {// > 0 表示升序if (cmp(array + i * width, array + j * width) > 0) {char tmp[width];memcpy(tmp, array + j * width, width);memcpy(array + j * width, array + i * width, width);memcpy(array + i * width, tmp, width);}}}
}void bubble_sort1(void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
{char *array = (char *)base;for (int i = 0; i < nel - 1; i++) {for (int j = 0; j < nel - i - 1; j++) {// > 0 表示升序if (cmp(array + j * width, array + (j + 1) * width) > 0) {char tmp[width];memcpy(tmp, array + j * width, width);memcpy(array + j * width, array + (j + 1) * width, width);memcpy(array + (j + 1) * width, tmp, width);}}}
}int main()
{Person people[] = {{"Alice", 18},{"Bob", 20},{"Charlie", 19},{"David", 18},{"Ella", 20}};int n = sizeof(people) / sizeof(Person);// 升序排序bubble_sort0(people, n, sizeof(Person), cmp_asc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}printf("\n");// 降序排序bubble_sort1(people, n, sizeof(Person), cmp_desc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}return 0;
}
// 实现一个自定义的模拟qsort函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char name[20];int age;
} Person;int cmp_asc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pa->name, pb->name);} else {return pa->age - pb->age;}
}int cmp_desc(const void *a, const void *b)
{Person *pa = (Person *)a;Person *pb = (Person *)b;if (strcmp(pa->name, pb->name) != 0) {return strcmp(pb->name, pa->name);} else {return pb->age - pa->age;}
}//交换 --一个字节一个字节的交换,共交换width次
void Swap(char* buf1, char* buf2, size_t width)
{size_t i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2))
{//冒泡排序//若要排序n个元素,只需要进行n-1趟//每一趟可以少比较一个元素,每一趟可以使一个元素在确定的位置上//num:要排序元素的个数 类型是size_t //num是无符号数 防止产生警告 所以i和j也定义为size_t// size_t == unsigned int size_t i = 0;size_t j = 0;//共进行num-1趟for (i = 0; i < num; i++){//每一趟for (j = 0; j < num - 1 - i; j++){//比较//传地址 //相邻两个元素比较 width:宽度,每个元素所占字节//排成升序if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//交换两数Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );}}}
}int main()
{Person people[] = {{"Alice", 18},{"Bob", 20},{"Charlie", 19},{"David", 18},{"Ella", 20}};int n = sizeof(people) / sizeof(Person);// 升序排序my_BubbleSort(people, n, sizeof(Person), cmp_asc);printf("Asc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}printf("\n");// 降序排序my_BubbleSort(people, n, sizeof(Person), cmp_desc);printf("Desc:\n");for (int i = 0; i < n; i++) {printf("Name: %s\t Age: %d\n", people[i].name, people[i].age);}return 0;
}
使用qsort对字符串数组进行排序:
// 使用qsort函数来对字符串数组进行升序和降序排序#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_STR_NUM 10
#define MAX_STR_LEN 20int cmpAsc(const void *a, const void *b)
{char **pa = (char **)a;char **pb = (char **)b;return strcmp(*pa, *pb);
}int cmpDesc(const void *a, const void *b)
{char **pa = (char **)a;char **pb = (char **)b;return -strcmp(*pa, *pb);return strcmp(*pb, *pa);
}int main()
{int n = 3;int i = 0;char **strs = (char **)malloc(n * sizeof(char *));char *str0 = (char *)malloc(100);for (i = 0; i < 3; ++i) {strs[i] = (char *)malloc(100);}snprintf(strs[0], 100, "ff str0\n");snprintf(strs[1], 100, "dd str1\n");snprintf(strs[2], 100, "aa str2\n");// 升序排序qsort(strs, n, sizeof(char *), cmpAsc);printf("\nAsc: \n");for(int i = 0; i < n; i++) {printf("%s", strs[i]);}printf("\n");// 降序排序qsort(strs, n, sizeof(char *), cmpDesc);printf("\nDesc: \n");for(int i = 0; i < n; i++) {printf("%s", strs[i]);}printf("\n");return 0;
}
// 使用qsort函数对字符串数组进行排序#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 在实际使用时,比较函数的参数应该根据实际情况转换为正确的指针类型。
// 在字符串数组中,每个元素都是指向一个字符串的指针,
// 因此需要将`const void *`类型的指针转换为`char **`类型的指针,即指向指针的指针,然后才能解引用该指针,
// 即使用`*(char **)a`,获取指向的字符串。
// 如果使用`(char *)a`进行强制类型转换,`char *`类型的指针是单层指针,而不是指针的指针。
// 这将导致在解引用该指针时不能得到正确的字符串指针,从而产生错误的答案。
// 因此,在使用指针数组中的字符串进行排序时,
// 必须使用`char **`类型的指针进行指针转换,再解引用该指针获取到正确的字符串指针进行比较,才能保证排序的正确性。
// a和b的值是strs的元素的地址,也就是指针的指针,所以void其实是char*,void*就是char**
// strs的每个元素都是一个指针,每个元素的地址就应该用指针的指针来存储
// 所以a和b就是指针的指针,所以void*就是char**,void想当于char*
int cmp(const void *a, const void *b)
{printf("a : %p, b : %p\n", a, b);char *tmpa = (char *)a;char *tmpb = (char *)b;char **tmpaa = (char **)a;char **tmpbb = (char **)b;printf("*tmpa: %s, **tmpaa:%s\n", tmpa, *tmpaa);printf("tmpa: %p, tmpb: %p, tmpaa: %p, tmpbb: %p\n",tmpa, tmpb, tmpaa, tmpbb);// 调试后发现:// a存放的是strs[0]的地址(char**类型)b存放的是strs[1]的地址(char**类型) // strcmp()会将p地址对应的内容转化成字符串,也就是将strs[0~2]的地址转化成字符串,将得到一个乱码// 因为将(char **类型的数据转换成了char *类型的数据,这样解引用出来的字符串当然是错误的// 因此得先把a,b转化成char**,这样解引用以后才是一个char*的地址// return strcmp(tmpa, tmpb);// return strcmp(*tmpaa, *tmpbb);// 用指针的方式进行排序return strcmp(*(char **)a, *(char **)b);// 不能将二级指针直接解引用,这样借用用后的值为1个一级指针,而不是一个字符串,// 因此需要转换成char **类型后在进行解引用操作// return strcmp((char *)a, (char *)b);
}int main()
{int n = 3;int i = 0;char **strs = (char **)malloc(n * sizeof(char *));char *str0 = (char *)malloc(100);for (i = 0; i < 3; ++i) {strs[i] = (char *)malloc(100);}printf("strs: %p, *strs: %p, strs[0]: %p, strs[1]: %p, strs[2]: %p\n",strs, *strs, strs[0], strs[1], strs[2]);printf("strs: %p, &strs[0]: %p, &strs[1]: %p, &strs[2]: %p\n",strs, &strs[0], &strs[1], &strs[2]);snprintf(strs[0], 100, "ff str0\n");snprintf(strs[1], 100, "dd str1\n");snprintf(strs[2], 100, "aa str2\n");printf("\nbefore sort:\n");for (i = 0; i < n; ++i) {printf("%s", strs[i]);}// 传入的参数为strs[0~2],即指针的指针qsort(strs, n, sizeof(char *), cmp);printf("\nafter sort:\n");for (i = 0; i < n; ++i) {printf("%s", strs[i]);}printf("\n");for (i = 0; i < n; ++i) {free(strs[i]);}free(strs);return 0;
}
通过以上代码可以活得一个经验,在进行字符串数组比时较需要注意如下问题:
不能在自定义的数据比较函数中return strcmp((char *)a, (char *)b);
而是应该return strcmp(*(char **)a, *(char **)b);
strs是一个指针数组,保存3个指针,也就是说&strs[0], &strs[1], &strs[2]都是二级指针,
地址分别为
0x555555757260
0x555555757268
0x555555757270
这3个二级指针分别各自保存1个一级指针,分别为strs[0], strs[1], strs[2]
指针的地址和保存的字串分别为:
0x5555557572f0 "ff str0\n"
0x555555757360 "dd str1\n"
0x5555557573d0 "aa str2\n"
而传入到cmp函数中的指针为二级指针&strs[0], &strs[1], &strs[2]
(用void *类型作为形参类型,并于不同类型数据的转换),
二级指针保存一级指针的地址对应关系为:
&strs[0]: 0x555555757260 -> strs[0]:0x5555557572f0 "ff str0\n"
&strs[1]: 0x555555757268-> strs[0]:0x555555757360 "dd str1\n"
&strs[2]: 0x555555757270-> strs[0]:0x5555557573d0 "aa str2\n"
若将传入的二级指针转换成char *类型,则接应用时去除的字符串是一个乱码,
因为二级指针保存的值为1个一级指针,所以接应用后的值仍然是一个一级指针,
而这个一级指针指向的内容才是需要获取的字符串。
相关文章:
c语言的qsort函数理解与使用
介绍:qsort 函数是 C 标准库中用于排序的快速排序算法函数。它的用法非常灵活,可以对任意类型的元素进行排序,只要提供了比较函数即可。 qsort 函数原型及参数解释: void qsort ( void* base, //指向要排序的数组的首元素…...
k8s集群增加nfs-subdir-external-provisioner存储类
文章目录 前言一、版本信息二、本机安装nfs组件包三、下载nfs-subdir-external-provisioner配置文件并进行配置1.下载文件2.修改配置 三、进行部署备注:关于镜像无法拉取问题的处理 前言 手里的一台服务器搭建一个单点的k8s集群,然后在本机上使用nfs-su…...
IT成长之路-ubuntu驱动篇
历时3天的蹂躏,总结驱动安装全面教程。 步骤一、安装gcc、g和make包 #脚本更新 sudo apt-get update #编译gcc sudo apt-get install gcc #编译g sudo apt-get install g #编译make sudo apt-get install make 注意: gcc、g版本可能会导致显卡驱动安…...
AI大模型如何赋能电商行业,引领变革
目录 1.概述 1.1. 购物推荐系统 1.2. 会员分类与客户细分 1.3. 动态商品定价 1.4. 库存和供应链管理 1.5. 客户服务与体验 1.6. 内容生成与管理 2.AI技术在电商中的创新应用 2.1.淘宝 2.2.京东 2.3.华为 2.4.小米 3.AI技术在提高电商平台销售效率方面发挥的作用 …...
QT6学习第四天 感受QT的文件编译
QT6学习第四天 感受QT的文件编译 使用纯代码编写程序新建工程 使用其他编辑器纯代码编写程序并在命令行运行使用 .ui 表单文件生成界面使用自定义 C 窗口类使用现成的QT Designer界面类 使用纯代码编写程序 我们知道QT Creator中可以用拖拽的方式在 .ui 文件上布局,…...
地平线 bev_cft_efficientnetb3 参考算法-v1.2.1
01 概述 在自动驾驶感知算法中 BEV 感知成为热点话题,BEV 感知可以弥补 2D 感知的缺陷构建 3D “世界”,更有利于下游任务和特征融合。 地平线集成了基于 bev 的纯视觉算法,目前已支持 ipm-based 、lss-based、 transformer-basedÿ…...
【linux】shell脚本
文章目录 1. jar包启动脚本1.1 方式一1.2 方式二 2. 进程关闭脚本3. 操作mysql4. impala建表语句提取5. 监控磁盘存量6. 清日志脚本7. 替换tomcat的启动端口8. 将一行数据按照空格依次读取 1. jar包启动脚本 1.1 方式一 #!/bin/sh RESOURCE_NAME/usr/local/applications/scre…...
构建一个去中心化的零售生态参与者的商业模型
在数字化和去中心化技术快速发展的背景下,传统零售行业正迎来革命性的转型。去中心化零售生态不仅让消费者、商家和内容创作者在同一平台上共同参与价值的创造和分配,还推动了零售体验、数据控制和社会互动的彻底变革。本文将探讨如何构建一个去中心化的…...
Spring Boot开发实战:从入门到构建高效应用
Spring Boot 是 Java 开发者构建微服务、Web 应用和后端服务的首选框架之一。其凭借开箱即用的特性、大量的自动化配置和灵活的扩展性,极大简化了开发流程。本文将以实战为核心,从基础到高级,全面探讨 Spring Boot 的应用开发。 一、Spring B…...
MyBatis(mybatis_plus)中TypeHandler的使用教程
MyBatis(mybatis_plus)中TypeHandler的使用教程 一.TypeHandler作用及其使用场景 在我们平常开发操作数据库时,查询、插入数据等操作行为,有时会报数据类型不匹配异常,就可以得知数据的类型是不唯一的必然是多种不同…...
【C++】IO库(三):string流
8.3 string 流 sstream 头文件定义了三个类型来支持内存 IO,这些类型可以向 string 写入数据,也可以从 string 读取数据,就像 string 是一个 IO 流一样。 istringstream 从 string 读数据;ostringstream 向 string 写入数据&…...
C# 反射详解
反射是C#中的一个强大特性,允许程序在运行时检查和操作类型和对象的信息。 通过反射,你可以获取类型的属性、方法、构造函数等信息,并可以动态创建对象、调用方法或访问属性,甚至可以实现某些框架或库的核心功能。 反射的基本概念…...
量化交易系统开发-实时行情自动化交易-8.量化交易服务平台(一)
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于收集整理的33个量化交易服…...
【开发商城系统】
在广西开发商城系统,可以按照以下步骤进行: 确定项目需求:与客户沟通,了解商城系统所需的功能和特性,并确定项目的预算和时间限制。 进行市场调研:了解广西地区的电商市场情况,包括竞争对手、消…...
C++设计模式-享元模式
动机(Motivation) 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作…...
Spark——安装步骤详细教程
1、安装步骤 1、上传 cd /opt/modules 2、解压 tar -zxf spark-3.1.2-bin-hadoop3.2.tgz -C /opt/installs 3、重命名 cd /opt/installs mv spark-3.1.2-bin-hadoop3.2 spark-local 4、创建软链接 ln -s spark-local spark 5、配置环境变量: vi /etc/prof…...
摆烂仙君传——深度学习秘境奇缘
第一章:深度学习秘境 在修仙界与科技交织的边缘,八荒六合九天无上摆烂仙君在其高科技修炼室中感应到一股神秘的召唤。这股力量似乎与他的灵魂产生了共鸣,引导他前往传说中的深度学习秘境。在那里,古老的仙法与前沿的算法交织&…...
C++设计模式:桥接模式(Bridge)
什么是桥接模式? 桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改…...
c++源码阅读__smart_ptr__正文阅读
文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. rele…...
halcon3D 1:1切片轮廓投影技术,透过像素距离,知实际物体的尺寸
首先说做个什么事儿 对一个物体的横截面进行1:1或者1:10的投影,也就是说世界物体1mm的话,投影到image中占1个或者10个像素值,这样,就可以透过直接计算image中的像素距离,知道实际物体的尺寸 用一张图说明是这样的。物…...
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法 1. npm库xss依赖的使用方法1.1 xss库定义1.2 xss库功能 2. vue3 中 wangeditor 使用xss库解决 XSS 攻击的方法和示例2.1 在终端执行如下命令安装 xss 依赖2.2 在使用 wangeditor 的地…...
计算机网络 实验七 NAT配置实验
一、实验目的 通过本实验理解网络地址转换的原理和技术,掌握扩展NAT/NAPT设计、配置和测试。 二、实验原理 NAT配置实验的原理主要基于网络地址转换(NAT)技术,该技术用于将内部私有网络地址转换为外部公有网络地址,从…...
UI设计-色彩、层级、字体、边距(一)
一.色彩:色彩可以影响人的心理与行动,具有不同的象征意义;有冷暖,轻重,软硬等等。 1.色彩情绪:最直观的视觉感受 一个活动的页面所用的颜色必须要与其内容相适应,让人看起来舒服。有时我们会不…...
【网络安全】
黑客入侵 什么是黑客入侵? “黑客”是一个外来词,是英语单词hacker的中文音译。最初,“黑客”只是一个褒义词,指的是那些尽力挖掘计算机程序最大潜力的点脑精英,他们讨论软件黑客的技巧和态度,以及共享文化…...
c++趣味编程玩转物联网:基于树莓派Pico控制有源蜂鸣器
有源蜂鸣器是一种简单高效的声音输出设备,广泛应用于电子报警器、玩具、计时器等领域。在本项目中,我们结合树莓派Pico开发板,通过C代码控制有源蜂鸣器发出“滴滴”声,并解析其中涉及的关键技术点和硬件知识。 一、项目概述 1. 项…...
【MySQL】MySQL从入门到放弃
文章目录 声明MYSQL一,架构1.1.网络连接层数据库连接池 1.2.系统服务层1.2.1.SQL接口1.2.2.存储过程1.2.3.触发器1.2.4.解析器1.2.5.优化器1.2.6.缓存,缓冲 1.3.存储引擎层1.4.文件系统层1.4.1.日志模块1.4.2.数据模块 二,SQL 执行2.1.执行流程2.2.刷盘2.3.返回 三.库表设计3.1…...
redis-cluster集群搭建
集群节点信息 192.168.222.131:46379 主要节点1 192.168.222.131:46380 从节点1 192.168.222.131:46381 从节点2192.168.222.132:46379 主要节点2 192.168.222.132:46380 从节点1 192.168.222.132:46381 从节点2192.168.222.133:46379 主要节点3 192.168.222.133:46380 从节点…...
C语言解决空瓶换水问题:高效算法与实现
标题:C语言解决空瓶换水问题:高效算法与实现 一、问题描述 在一个饮料促销活动中,你可以通过空瓶换水的方式免费获得更多的水:3个空瓶可以换1瓶水。喝完这瓶水后,空瓶会再次变为空瓶。假设你最初拥有一定数量的空瓶&a…...
单例模式入门
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的…...
MongoDB快速入门
1 MongoDB 1.1 MongoDB 概念 1.1.1 什么是 MongoDB MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档数据库,由C语言编写。 目的是为了解决数据大量增长的时候系统的可扩展性和敏捷性。MongoDB要比传统的关系型数据库简单很多。 在Mo…...
c语言中的extern是什么
在C语言中,extern 是一个关键字,用于声明变量或函数的外部链接。它告诉编译器该变量或函数的定义在其他文件中,编译器在编译当前文件时并不需要知道变量或函数的具体定义,而是将它们视作外部引用。 1. 变量的 extern 声明 当你在…...
CTF之密码学(摩斯密码)
一、历史背景 摩尔斯电码发明于1837年,是一种早期的数字化通信形式。它最初由艾尔菲德维尔和摩尔斯等人构思,通过点、划和中间的停顿,把各个字元以及标点符号彼此独立地发送出去。这种标识不同符号的方案后来被放入摩尔斯的专利中࿰…...
Flink 任务启动脚本-V2(包括ck启动)
#!/bin/bash#crontab时设置,如果依赖其他环境变量配置,可以在脚本执行一下环境变量脚本 source /etc/profile# 进入脚本目录 curdirdirname "$0" curdircd "$curdir"; pwd echo "进入启动脚本目录 $curdir"# 定义应用程序…...
16:00面试,16:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
selinux和防火墙
SElinux 1、selinux简介 SELinux是Security-Enhanced Linux的缩写,意思是安全强化的linux。 SELinux 主要由美国国家安全局(NSA)开发,当初开发的目的是为了避免资源的误用。 SELinux是对程序、文件等权限设置依据的一个内核模块。…...
Android 13 Aosp Settings Android Studio版本
Android 13 Aosp Settings Android Studio版本 Settings相关源码 Settings https://android.googlesource.com/platform/packages/apps/Settings/+/refs/heads/android13-release SettingsIntelligence https://android.googlesource.com/platform/packages/apps/SettingsIn…...
[241127] Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!| TrendForce 预测 2025 十大科技趋势
目录 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!TrendForce 预测 2025 十大科技趋势 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手! Mistral AI 宣布对其免费 AI 助手 Le Chat 进行重大更新,新增多项强大功能&…...
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。 carbon 目前已捐赠给 dromara 开源组织,已被 awesome-go 收录&am…...
linux安全管理-账号口令
文章目录 1 设备密码复杂度策略2 设备密码生存周期、最小长度、更改最小间隔天数和过期前警告天数3 使用 PAM 认证禁止指定组之外的用户使用 su 切换到 root4 制作用户权限对照表 1 设备密码复杂度策略 1、配置内容 检查密码复杂度策略中设置的特殊字符、大写字母、小写字母和…...
uni-app自定义底部tab并且根据字段显示和隐藏
首先将所有tab使用到的页面创建好并且在pages里面配置好,要在pages.json中的"tabBar里面配置"custom": true将自带的tab底部导航关闭 "pages": [{"path": "pages/mine/mine","style": {"navigationBa…...
C#开发合集
用C#轻松搞定m3u8视频下载与合并 嘿,程序员们!今天咱们来聊聊如何用C#写个小程序,轻松下载和合并m3u8视频文件。没错,就是那种分段的流媒体视频。准备好了吗?让我们开始吧! 准备工作 在动手之前…...
Chrome和edge浏览器如何为任何网站强制暗模式
前言 因为我的编辑器是黑色,可能是看的时间长了比较喜欢这种颜色了,感觉白色有些刺眼。尤其是看文章时,两边的空白纯白色,所以强迫症搜素设置了谷歌浏览器和edge如何设置成黑色。 Chrome和edge浏览器如何为任何网站强制暗模式 前…...
第二十章 Java多线程--JUC并发工具-CountDownLatch
目录 一、CountDownLatch基础概念 CountDownLatch 的核心概念 CountDownLatch 的常用方法 场景一:主线程等待多个子线程执行完毕 场景二:实现多个线程同时开始执行任务 场景三:统计报表优化 CountDownLatch 的局限性 结论 二、Count…...
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。通常,etcd 只应当对 Kubernetes 控制平面的组件(如 API Server、Controller Manager、Scheduler 等)以及某些维护工具(如备份工具)开放访问权限&…...
shell脚本基础学习_总结篇(完结)
细致观看可以,访问shell脚本学习专栏,对应章节会有配图https://blog.csdn.net/2201_75446043/category_12833287.html?spm1001.2014.3001.5482 导语 一、shell脚本简介 1. 定义: 2. 主要特点: 3. shell脚本的基本结构 4. S…...
Linux之网络基础
网络发展 网络的发展可以从人与人之间的工作模式开始谈起, 人与人的工作模式反应了机器与机器的工作模式: 1. 独立模式: 在网络发展的早期计算机间处于独立模式, 计算机之间相互独立 最开始计算机之间是独立运行的, 数据之间的交互需要人用软盘等存储介质拷贝过去, 一般涉及…...
《Vue零基础入门教程》第十课:属性绑定指令
往期内容 《Vue零基础入门教程》第一课:Vue简介 《Vue零基础入门教程》第二课:搭建开发环境 《Vue零基础入门教程》第三课:起步案例 《Vue零基础入门教程》第四课:应用实例 《Vue零基础入门教程》第五课:挂载 《…...
RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange
前言: RabbitMQ 延迟队列插件(rabbitmq_delayed_message_exchange)是一个社区开发的插件,它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件,用户可以创建一种特殊的交换机类型 x-delayed-message,该…...
MATLAB中Simulink的基础知识
Simulink是MATLAB中的一种可视化仿真工具, 是一种基于MATLAB的框图设计环境,是实现动态系统建模、仿真和分析的一个软件包,被广泛应用于线性系统、非线性系统、数字控制及数字信号处理的建模和仿真中。 Simulink提供一个动态系统建模、仿真和…...
Swift——单例模式
单例是软件设计常用的一种模式,它的核心结构中只有一个被称为单例的特殊类,通过单例模式可以保证应用该模式的类只有一个实例化对象,其作用就是能够使类中的一个对象成为系统中的唯一实例。 单例的特点: 某个类只有一个实例化对象…...