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

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函数理解与使用

介绍&#xff1a;qsort 函数是 C 标准库中用于排序的快速排序算法函数。它的用法非常灵活&#xff0c;可以对任意类型的元素进行排序&#xff0c;只要提供了比较函数即可。 qsort 函数原型及参数解释&#xff1a; void qsort ( void* base, //指向要排序的数组的首元素…...

Java 语言的起源发展与基本概念(JDK,JRE,JVM)

Java语言的起源 源起 Java语言最初是由Sun Microsystems公司&#xff08;该公司于2009年被Oracle公司收购&#xff09;开发的一种编程语言。其创造者是詹姆斯高斯林&#xff08;James Gosling&#xff09;&#xff0c;他是一位加拿大计算机科学家。其前身名为Oak&#xff08;橡…...

03_变量

变量 var num 10; 变量的重新赋值 var num10; num 20; 变量提升 JavaScript 引擎的工作方式是&#xff0c;先解析代码&#xff0c;获取所有被声明的变量&#xff0c;然后再一行一行地运行。这造成的结果&#xff0c;就是所有的变量的声明语句&#xff0c;都会被提升到代码的…...

[论文阅读-综述]Supervised Speech Separation Based on Deep Learning: An Overview

基于深度学习的监督语音分离&#xff1a;综述 出版&#xff1a;IEEE 核心&#xff1a;使用语音分离将目标语音信号与噪声混合分离的计算 本文用于对该文章的学习&#xff0c;主要是对内容的理解翻译与笔记 1. 语音分离介绍 语音分离的目标&#xff1a;将目标语音与背景干扰分…...

群控系统服务端开发模式-应用开发-邮箱配置功能开发

邮箱配置主要是将管理员数据做归属。具体见下图&#xff1a; 一、创建表 1、语句 CREATE TABLE cluster_control.nc_param_mail (id int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 编号,title varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT…...

【机器学习】——卷积与循环的交响曲:神经网络模型在现代科技中的协奏

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…...

android studio引用so库

在工程中编译好的so库文件将在原始编译工程对应目录下&#xff1a;build/intermediates/cxx/Debug/xxxxxx/obj/ 其目录结构如上所示&#xff0c;包含生成的四个版本&#xff0c;每个文件夹下均包含c/c源码编译成的Android版本的libnavi.so库和提供应用接口的libnavi-lib.so库。…...

2024年信号处理与神经网络应用(SPNNA 2024)

会议官网&#xff1a;www.spnna.org 会议时间&#xff1a;2024年12月13-15日 会议地点&#xff1a;中国武汉...

wxWidgets-ImageView

wxWidgets实现图片浏览、放大缩小、另存为新的图片格式等 #include "wx/wxprec.h"#ifndef WX_PRECOMP#include "wx/wx.h" #endif#include "wx/filename.h" #include "wx/zstream.h"#include "imageviewctrl.h"class MyFrame…...

第1章-JVM和Java体系架构

虚拟机 虚拟机概念 所谓虚拟机&#xff08;Virtual Machine&#xff09;&#xff0c;就是一台虚拟的计算机。它是一款软件&#xff0c;用来执行一系列虚拟计算机指令。大体上&#xff0c;虚拟机可以分为系统虚拟机和程序虚拟机。 大名鼎鼎的Virtual Box&#xff0c;VMware就属…...

windows 服务器角色

windows 服务器角色 Active Directory Rights Management Services Active Directory RightsManagement Services (AD RS)帮助保护信息&#xff0c;防止未授权使用。AD RMS 将建立用户标识&#xff0c;并为授权用户提供受保护信息的许可证。 ServicesActive Directory 联合身…...

[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式

T. 已测试目录 主机类型主机版本Docker镜像版本结果WSL2Ubuntu22.04Ubuntu20.04PASSWSL2Ubuntu22.04Ubuntu18.04PASS R. 软硬件要求&#xff1a; 编译硬件需求&#xff1a;做多系统测试&#xff0c;磁盘500GB起步(固态)&#xff08;机械会卡死&#xff09;&#xff0c;内存3…...

C#中判断两个 List<T> 的内容是否相等

ET实现游戏中邮件系统逻辑思路&#xff08;服务端&#xff09;_游戏邮件系统设计-CSDN博客 场景&#xff1a;今天遇到一个BUG&#xff0c;在服务器重启的时候&#xff08;体验服&#xff09;&#xff0c;玩家之前接收的邮件又重新接收了一次&#xff0c;但是两封邮件的ID是不同…...

Linux环境下配置neo4j图数据库

1.下载安装包 openjdk-11.0.1_linux-x64_bin.tar.gz neo4j-community-4.2.19-unix.tar.gz 2.之前配置好的配置文件 neo4j.conf 3.安装 3.1-jdk11的安装&#xff08;jdk1.8不够用&#xff09; 解压缩 tar -zxvf openjdk-11.0.1_linux-x64_bin.tar.gz修改系统环境变量 打开pro…...

Windows 11 搭建 Docker 桌面版详细教程

在当今的软件开发与部署领域&#xff0c;Docker 已成为一项极为重要的容器化技术。它能够让开发者轻松地打包应用及其依赖项&#xff0c;实现跨环境的一致性运行&#xff0c;大大提高了开发效率与部署的便捷性。本教程将详细介绍在 Windows 11 操作系统上搭建 Docker 桌面版的具…...

Pytest-Bdd-Playwright 系列教程(13):钩子(hooks)

Pytest-Bdd-Playwright 系列教程&#xff08;13&#xff09;&#xff1a;钩子&#xff08;hooks&#xff09; 前言一、什么是钩子&#xff1f;二、Pytest-Bdd 提供的钩子一览三、钩子用法详解1. pytest_bdd_before_scenario2. pytest_bdd_after_scenario3. pytest_bdd_before_s…...

dns 服务器简单介绍

dns 服务器分类&#xff1a; 根域名服务器顶级域名服务器权威域名服务器本地域名服务器 dns 的查询过程 国内优秀公共域名 腾讯&#xff1a;DNSPod-免费智能DNS解析服务商-电信_网通_教育网,智能DNS-烟台帝思普网络科技有限公司 119.29.29.29 和 182.254.118.118 阿里&#xf…...

Neo4j图形数据库-Cypher中常用指令

一、创建与修改 1.1 create 创建图数据库中的节点、关系等元素&#xff1a; CREATE (:Person {name: "Alice", age: 30}) CREATE (p1:Person {name: "Bob"})-[r:KNOWS]->(p2:Person {name: "Charlie"})批量创建元素 CREATE (n1:Node),(n2…...

linux安全管理-防火墙配置

1. 开启系统防火墙 1、检查内容 检查操作系统是否开启防火墙&#xff1b; 2、配置要求 操作系统开启防火墙&#xff1b; 3、配置方法 systemctl status firewalld ##查看系统防火墙运行状态 systemctl start firewalld ##启动防火墙 systemctl restart firewalld ##重启防火墙…...

什么是BIOS

BIOS&#xff08;Basic Input/Output System&#xff0c;基本输入输出系统&#xff09;是计算机启动过程中的一个关键组件&#xff0c;主要负责硬件的初始化和系统的引导。以下是关于 BIOS 的一些详细信息&#xff1a; 1. 基本功能 硬件初始化&#xff1a;当计算机启动时&…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...