qsort:我很强,了解一下(详解过程)

news/2024/5/14 17:22:57/文章来源:https://blog.csdn.net/m0_64212811/article/details/127061735

了解qsort,以及模拟实现

  • 🎑情境引入
  • 🎈qsort
    • 📖qsort的头文件
    • 📄开场
    • 🔑qsort的参数
      • 🤔为什么可以对任意类型排序呢?
      • 📜参数
        • 参数①
        • 参数②
        • 参数③
      • 最难的参数④
    • 🎃qsort应用实例
      • 🌳比较整形/浮点型
      • 🌴比较结构体的整形
      • 🌵比较结构体的字符串
  • 💡想成为一名优秀的程序猿,需要加点难度---- 模拟实现
    • 🎈冒泡排序模拟实现
      • ✏普通版本的冒泡排序
    • 📄重点来了
      • 🎉先对比较进行转换
        • 🎐该决解的问题已经解决,那开始实现----比较
      • 🎉最后一步交换的实现
        • 🩸问题解决开始实现----交换
  • 🛠冒泡排序模拟实现qsort完整代码
  • 🎈插入排序实现qsort
    • 🎠原版插入排序
    • ✨关键处分析
  • 结束语

在这里插入图片描述

🎑情境引入

struct student
{char name[10];int age;
};

你是否有过这样的经历,在对结构体成员进行排序,需要写几个排序,而感到不耐烦呢。
就比如对上面的结构体数组排序,既要对成员name排序,又要对成员age排序。
看了这篇博客,你就可以告别大段落式的排序啦。
qsort表示它很强,它来拯救你了~~❤

qsort强在哪呢?
强在它可以对任意类型的排序(存储结构需要限定–顺序存储)
也就是说qsort只能对顺序存储的结构进行排序。
顺序存储结构有:1.数组,2.在堆区开辟一段连续的空间

🎈qsort

📖qsort的头文件

#include<stdlib.h>

📄开场

qsort底层原理是快排,但在这篇博客中不讲快排,而是讲冒泡排序,以及插入排序去模拟qsort的功能。

为啥还要讲插入排序呢,如果你想对单链表进行排序的话,qsort是不能达到目的的,对于单链表的排序,需要用插入排序的思想进行排序。

通过插入排序模拟qsort,再对存储复杂数据的单链表排序的时候,会轻松很多。

🔑qsort的参数

在这里插入图片描述

size_t 是 unsigned int 重命名后的类型名

🤔为什么可以对任意类型排序呢?

主要是在设置函数参数的时候,使用的是void*。
void* 有个特点,叫“有容乃大”。
void
* 可以接收任意类型的指针
同样的任意类型的指针也可以接收void*

在这里插入图片描述

在void* 修饰的变量接收任意类型的指针的情况下,该变量是不能进行任何操作的。

因为对指针进行操作是看指针的类型,该变量的类型是void* 。
因为void类型大小是不确定的(vs下0,linux下1)。
那么对该变量进行*或者加减整数操作是没有意义的
指针类型的意义不记得的点这

那如何解决呢?只需要通过强制类型转换即可。

📜参数

参数①

对于参数①void* base 通过void* 就能够推测一些东西了。void*是指针,是用来接收地址的。
那么在调用qsort的时候,第一个实参一定是个地址。这样理解是没错的,也确实如此。
实参传①就是你想要排序数组的起始地址(或者在堆区开辟空间的起始地址)

参数②

对于参数②size_t num,表示你需要排序的数组有多少个元素个数

参数③

对于参数③ size_t size,表示待排序数组元素的大小(单位是字节)
为什么需要传元素的大小呢?也很好理解,我们需要对不同类型的元素进行排序,不同的类型,所占空间的大小是不同的,如果不传元素的大小,qsort又怎么能对不同类型元素进行排序呢?所以必须传。

最难的参数④

参数④ int (*compar)(const void*, const void*))这也是我们能够比较任意类型的关键!
有人看到这个参数感觉头皮发麻,不知道这是啥。先来分析一下。
我们先把中间部分换个形式int fun (const void*, const void*))
这是啥?这是一个函数!
函数名是fun形参为(const void*, const void*)返回类型为int
在回过头来分析int (*compar)(const void*, const void*)),那这是什么?这是指针,因为操作符*,并且与()优先结合,所以是指针。
再结合上面所说,这个指针指向的是一个函数。

有人可能难以理解指向的是函数,那我再说说,请问函数有地址吗?答案是有的。

在这里插入图片描述

在多说几嘴,函数名也是可以直接表示函数的地址,也可以不用&。

在这里插入图片描述

已经知道函数是有地址的了,那指针去指向一个函数,也就没什么问题的了。看下面这段话,再去理解一番。

看这个表达式 int* p
p指向谁?如果你不知道怎么看的话,把指针名p和*去掉,剩下的就是指针指向某个变量的类型。也就是说p将来指向的是一个int类型的变量(不考虑强制类型转换)

那么再回过头来看int (*compar)(const void*, const void*)),把指针名compar*去了,剩下的是 int (const void*, const void*))这是一个函数。按照上面的理解,该指针在将来是指向一个函数的,那么现在应该能理解指针为啥指向函数了吧

综上所述,参数④是一个函数指针,该指针指向了一个函数,该函数的形参为(const void*, const void*),该函数的返回类型为int

接着分析,既然知道了参数④是一个函数指针,是指针,那么传参的时候肯定是需要传地址,传谁的地址?传函数的地址!

换句话说,如果我们想要使用qsort函数,那么我们需要一个形参一致,返回类型一致的函数这个函数是需要使用qsort的人自己去实现的。因为只有使用qsort的人才知道自己想要比较什么,比较元素的类型又是什么。

那这个函数的返回值又有什么含义呢。
比较的两个元素分别e1,e2。
如果e1大于e2,返回一个大于0的数
如果e1小于e2,返回一个小于0的数
如果e1等于e2,返回0

在这里插入图片描述

那使用qsort的人去实现的这个函数作用是什么?是比较方法,不同的类型比较的方式是不同的!如果是数与数之间的比较,做差即可。如果是字符之间的比较呢?做差就不适合了,需要使用strcmp

讲了这么多,相信你应该有所了解,或许还不太理解,也没关系,通过下面的实例来理解上面我所说的!

🎃qsort应用实例

主函数

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct S   //定义一个结构体类型
{char name[10];int age;
};
int main()
{test1();test2();return 0;
}

🌳比较整形/浮点型

数与数之间的比较做差即可。
返回值也就是这个差值。
写的时候注意要强制类型转换,转换成什么类型的指针取决于你想要比较的元素类型,比较的是int类型就int*,比较的是float类型就float*

int int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;//e1-e2排的是升序//降序的话,需要将e1,e2换个位置
}
void test1()
{int arr[10] = { 5, 2, 1, 3, 4, 6, 9, 8, 7, 10 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), int_cmp);//arr是数组的地址,sz是数组元素的个数//sizeof(arr[0]),元素所占空间的大小//int_cmp,是函数的地址,该函数是使用qsort的人去实现int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}

在这里插入图片描述
在这里插入图片描述

🌴比较结构体的整形

在对结构体排序的时候,需要注意的是 ()
(struct S*)e1->age这样写是不行的,需要将(struct S*)e1 当作一个整体去使用,需要加上 ()
写成((struct S*)e1)->age

int age_cmp(const void* e1, const void* e2)
{return ((struct S*)e1)->age - ((struct S*)e2)->age;
}
void test2()
{struct S s[] = { {"Zhang",40},{"Wang",20},{"Lisi",60} };//对结构体初始化int sz = sizeof(s) / sizeof(s[0]);//求数组的元素个数qsort(s, sz, sizeof(s[0]), age_cmp);//sizeof(s[0]),一个元素的大小//age_cmp,函数的地址。int i = 0;for (i = 0; i < sz; i++){printf("%s %d\n", s[i].name, s[i].age);}
}

在这里插入图片描述

🌵比较结构体的字符串

对一些字符串函数不了解的点这

这里还是要强调一下,注意 ()
strcmp()本身也是有个括号的。
strcmp的返回值:大于返回一个大于0的数,小于返回小于0的数,等于返回0。
写的时候可以先从里面的写起
先把(struct S*)e1)->name, ((struct S*)e2)->name写出来,然后在复制粘贴到strcmp()的()里。

int name_cmp(const void* e1, const void* e2)
{return strcmp(((struct S*)e1)->name, ((struct S*)e2)->name);   
}
void test2()
{struct S s[] = { {"Zhang",40},{"Wang",20},{"Lisi",60} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), name_cmp);int i = 0;for (i = 0; i < sz; i++){printf("%s %d\n", s[i].name, s[i].age);}
}

在这里插入图片描述

💡想成为一名优秀的程序猿,需要加点难度---- 模拟实现

🎈冒泡排序模拟实现

冒泡排序比较简单,这里就不再赘述如何来的了。
通过与普通版本的冒泡排序,对比去实现qsort的功能

✏普通版本的冒泡排序

void Bubble_sort(int* arr, int sz)
{int i = 0;for (i = 0; i < sz - 1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1])//比较{//交换int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

模拟实现的函数可以对着qsort的去写
这个比较容易 void Bubble_sort2(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))

📄重点来了

冒泡排序中最主要的两个步骤是 比较 + 交换。

		if (arr[j] > arr[j + 1])//比较{//交换int tmp = arr[j];arr[j] = arr[j + 1];			arr[j + 1] = tmp;	}

🎉先对比较进行转换

友情提示,需要对指针类型的意义要有所了解才能理解
不了解的点击"我"

base的类型是void*上面有铺垫过,void*不可直接使用,需要通过强制类型转换。那转换成什么呢?转换成int*合适吗?

显然不合适,这样写,那我们如何实现比较任意类型的呢?

回归本源,内存的基本单位是字节,不管是哪种类型的元素,元素所占空间的大小肯定是可以确定的。

那我们可以这样:以字节为单位去偏移,虽然每一次偏移的步长只有1个字节,但只要我们知道了,一个元素所占空间的大小有n个字节。

那从当前位置向后偏移n次,不就是n个字节嘛?不就能够在内存中取到一个元素的吗?

这样一理,base需要强制类型转换为char*,那类型的大小如何得知呢?不正是我们的参数③–>size_t size

或许你还没理解,用图带你理解一下。

在这里插入图片描述
在这里插入图片描述

那现在还有一个问题那如何取到每一个元素呢?

在这里插入图片描述

数组与指针访问是互通的(操作符之间可以互用),不了解点"我"

原先的是这样写的if (arr[j] > arr[j + 1]) (指针类型是int*)我们是不是可以借鉴一下呢?
arr[j]等价于*(arr+j)
arr+j的含义是以arr为起始地址+j向后偏移j*4个字节和我们写的(char*)base+size(含义是以base为起始地址向后偏移size个字节)
相比,不就少了什么不就少了j*吗,那我们这样写(char*)base+size*j和上面arr+j所表达的意思不就一样了吗?

还有一种理解,我们已经知道(char*)base+size表示的是第一个元素(是以base为起始地址的第一个元素)那第二个元素不就是(char*)base+size + (char*)base+size,第三个元素是(char*)base+size + (char*)base+size + (char*)base+size,那第j个元素不就是(char*)base+size * j 吗?

怎么理解方便就怎么选择。

元素每一个元素能够取出来了,那该如何比较呢?

轮到我们所写的比较函数出场了。比较方法的函数已经有了,我们只需要传参即可。这样调用的函数又被称为回调函数

哪种调用呢? 以指针的形式去调用函数,这个函数就被称为回调函数

这里的指针可以不用解引用,直接当作函数来使用。
为什么可以这样呢?还记得上面有说过,函数名就表示函数的地址, 这个地址不就是指针吗?那这个指针不就是函数名吗?函数调用是函数名(参数),这样一换不就是 指针(参数)

🎐该决解的问题已经解决,那开始实现----比较

if ( cmp((char*)base + j * width, (char*)base + (j + 1) * width) )

我这样写对吗?答案是不对,还少了点东西。我们这个函数返回值是一个整数,并不是 大于,小于,等于! 要加上判断

if ( cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0 )

或许有人会有疑问,为什么在对比较函数中,传参只需要传地址,就可以比较两个元素的大小。

这是指针类型的作用,指针的类型决定了解引用(*)能够操作多大的空间。

比较函数是使用者实现的,对应的元素类型也是明确的,在接收地址后,根据强制类型转换后的类型,进行解引用操作,可以取到对应的元素内容,那也就能完成比较。

🎉最后一步交换的实现

交换步骤先来看原冒泡的实现

	    //交换int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;

按照上面已经有的经验,想要实现对任意类型元素的交换,我们仍然只能通过强制类型转换为char*以字节为单位去实现。

如果你曾经有模拟实现过strcpy的话,那现在这个问题对你来说很容易就能完成的。

没有模拟过的话,且听我分析。
交换是两个元素互换,交换实现的步骤是以字节为单位,一个字节一个字节的交换,循环的条件应该是很容易想到的,什么时候交换完成了呢?当一个元素中最后一个字节交换后就完成了一次交换。

这里有一堆的字符串函数等着你来模拟实现,其中有两个是挺有难度的噢,快点“我”~

整个想法有了,也可以开始实现了。如果我们把这一“动作”封装成函数是不是更显得"高大上"呢?也确实可以这样实现,而且也美观。
函数名为Swap形参和返回类型是什么呢?
返回类型容易考虑我们不需要返回类型。
那形参是啥?比较的是两个元素,这两个肯定需要传过去。
再加上我们是以字节为单位进行交换的,那结束的条件也需要传,结束条件就是我们元素的大小。
讲到这那已经可以开始实现了。

🩸问题解决开始实现----交换

//函数调用(交换两个元素,以及元素的大小)
Swap( (char*)base + j * width ,(char*)base + (j + 1) * width ,width );//函数实现,选择哪种循环都行。
void Swap(char* e1,char* e2, int width)
{int i = 0;for(i=0;i<width;i++){char tmp = *e2;*e2 = *e1;*e1 = tmp;e1++;e2++;}
}

🛠冒泡排序模拟实现qsort完整代码

void Swap(char* e1, char* e2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *e2;*e2 = *e1;*e1 = tmp;e1++;e2++;}
}
void Bubble_sort2(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{int i = 0;for (i = 0; i < sz - 1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){Swap((char*)base + j * width,(char*)base + (j + 1) * width,width);}}}
}

同样可以来测试一下


int int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void test1()
{int arr[] = { 2,5,3,1,9,6,4,8,7,10 };int sz = sizeof(arr) / sizeof(arr[0]);Bubble_sort2(arr, sz, sizeof(arr[0]), int_cmp);print(arr, sz);
}struct S
{char name[10];int age;
};
int struct_name_cmp(const void* e1, const void* e2)
{return strcmp(((struct S*)e1)->name, ((struct S*)e2)->name);
}int struct_age_cmp(const void* e1, const void* e2)
{return ((struct S*)e1)->age - ((struct S*)e2)->age;
}
void test2()
{struct S s[] = { {"Zhang",40},{"Li",20},{"Wang",50} };int sz = sizeof(s) / sizeof(s[0]);//Bubble_sort2(s, sz, sizeof(s[0]), struct_name_cmp);Bubble_sort2(s, sz, sizeof(s[0]), struct_age_cmp);int i = 0;for (i = 0; i < sz; i++){printf("%s  %d\n", s[i].name, s[i].age);}
}
int main()
{//test1();test2();return 0;
}

对结构体年龄排序

在这里插入图片描述

对结构体姓名排序
在这里插入图片描述
对数组排序
在这里插入图片描述

🎈插入排序实现qsort

🎠原版插入排序

void Insert(int* arr, int sz)
{int i = 1;for (i = 1; i < sz; i++){int t = arr[i];//待插入的元素int j = i - 1;while (j >= 0 && t < arr[j]){//交换arr[j + 1] = arr[j];j--;}arr[j + 1] = t;}
}
int main()
{int arr[10] = { 5,2,3,8,9,4,7,1,10,6 };int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;Insert(arr, sz);for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

✨关键处分析

插入排序需要注意的是这两个表达式int t = arr[i];arr[j + 1] = t;为了达到实现任意类型的排序,肯定不能这样写。

那我是这样处理的:

为了存储插入的元素,你需要空间,需要多大根据元素的类型的大小。
我首先想到的是用动态内存函数,通过malloc开辟空间来存储要插入的元素。地址的类型需要设置为char*

另外如何实现赋值这一过程呢?
如果写过strcpy的模拟实现那应该也能够想到,我们可以通过Copy函数进行拷贝,就相对于完成了一次赋值。

一些函数的模拟实现写一遍,自己有更深的理解,很容易能想到,多去模拟实现这些函数也能提升自己代码能力。
点"我“,即可找到那些模拟的字符串函数

void Swap(char* e1, char* e2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *e2;*e2 = *e1;*e1 = tmp;e1++;e2++;}
}
void Copy(char* e1, const char* e2, int width)
{while (width){*e1 = *e2;e1++;e2++;width--;}
}void Insert2(void* base, int num, int size, int(*cmp)(const void* e1, const void* e2))
{int i = 1;char* t = (char*)malloc(size);if(NULL==t)//检测开辟是否成功{perror("malloc");return;}for (i = 1; i < num; i++){//拷贝赋值Copy(t, (char*)base + size * i, size);int j = i - 1;//比较while (j >= 0 && cmp(t, (char*)base + size * j) < 0){//交换Swap((char*)base + size * (j + 1), (char*)base + size * j, size);j--;}//拷贝赋值Copy((char*)base + size * (j + 1), t, size);}//对堆区开辟的空间释放free(t);//指针置为空,避免野指针t=NULL}

测试

int struct_name_cmp(const void* e1, const void* e2)
{return strcmp(((struct S*)e1)->name, ((struct S*)e2)->name);
}int struct_age_cmp(const void* e1, const void* e2)
{return ((struct S*)e1)->age - ((struct S*)e2)->age;
}int cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void test2()
{struct S s[] = { {"Zhang",40},{"Li",20},{"Wang",50} };int sz = sizeof(s) / sizeof(s[0]);Insert2(s, sz, sizeof(s[0]), struct_name_cmp);Insert2(s, sz, sizeof(s[0]), struct_age_cmp);int i = 0;for (i = 0; i < sz; i++){printf("%s  %d\n", s[i].name, s[i].age);}
}void test1()
{int arr[10] = { 5,2,3,8,9,4,7,1,10,6 };int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;Insert2(arr,sz,sizeof(int),cmp_int);for (i = 0; i < 10; i++){printf("%d ", arr[i]);}
}
int main()
{//test1();test2();return 0;
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结束语

看完之后,还等什么呢,快点自己模拟实现一下属于你的qsort吧~

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

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

相关文章

一个完全纯净的windows资源站

网址:https://hellowindows.cn/ hello Windows呢是一个纯净的Windows系统下载网站&#xff0c;从已经淘汰的xp到新推出的win11&#xff0c;大部分的系统版本都涵盖了 且都是中文版本,更加方便 windows server版本也包括在内哦

17 -- 排序算法之希尔排序

希尔排序算法介绍: 希尔排序是希尔于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。 写入排序法的基本思想: 希尔排序十八记录按下标的一定增量分组,对每组使用直接插入算法排序:随着增量逐渐…

JAVA毕设项目京东仓库管理系统(Vue+Mybatis+Maven+Mysql+sprnig+SpringMVC)

JAVA毕设项目京东仓库管理系统&#xff08;VueMybatisMavenMysqlsprnigSpringMVC&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&am…

好心情精神心理科医生:哪些精神类药物会影响你的睡眠?

患病后的你是否也因有这种顾虑&#xff0c;迟迟不敢吃药或选择停药呢&#xff1f; 到底哪些精神科药物会引起睡眠问题呢&#xff1f;资料显示&#xff0c;凡是提高多巴胺能和去甲肾上腺素能的药物&#xff0c;都有可能引起睡眠问题。今天&#xff0c;好心情小编带大家一起来看…

G:\r\tcga_example-master\scripts 生存分析 tcgaexample jimmy

G:\r\tcga_example-master\scripts library(survival) library(survminer)## 批量生存分析 使用 coxph 回归方法 # http://www.sthda.com/english/wiki/cox-proportional-hazards-model colnames(phe) head(phe) #event中1 表示存活&#xff08;终点事件&#xff09; #htt…

15Spring Boot整合MyBatis

MyBatis 是一个半自动化的 ORM 框架&#xff0c;所谓半自动化是指 MyBatis 只支持将数据库查出的数据映射到 POJO 实体类上&#xff0c;而实体到数据库的映射则需要我们自己编写 SQL 语句实现&#xff0c;相较于Hibernate 这种完全自动化的框架&#xff0c;Mybatis 更加灵活&am…

windows下Redis多实例部署

当存在多个项目的时候&#xff0c;需要同时部署时&#xff0c;且只有一台服务器时&#xff0c;哪么就需要部署Redis多个实例&#xff0c;原理很简单&#xff0c;多个Redis服务运行使用不同的配置及数据管理。 具体操作如下&#xff1a; 1、进入redis安装目录&#xff0c;找到…

zerotier的planet服务器(根服务器)-搭建教程

应用场景介绍: 利用阿里云服务器,搭建根服务器,把不同局域网打通,实现内网穿透,远程控制。 准备工具: 1、服务端:云服务器(有公网IP)Centos 7.62、客户端: 工控机(或者家里电脑)(Linux) ,公司电脑Windows 搭建私有化 ZeroTier步骤: 一、云服务器上安装服务操作…

python如何制作并安装自建包?

一、依赖 首先检查python是否安装了wheel、setuptools包,没有则使用pip安装pip install wheel --force-reinstallpip install setuptools --force-reinstall 二、准备文件在create_package文件夹下,制作自定义包(myPackage): 在该包下,有aa.py和bb.py两个模块, 同时该包…

win11怎么回去win10?四种方法教你!

win11系统与旧系统相比&#xff0c;在这些方面进行了重大更新&#xff1a;新的开始菜单、通知中心、重新设计的任务栏以及更加美观的圆角窗口&#xff0c;确实给用户带来了不一样的体验。然而&#xff0c;win11有时漏洞频出、BUG不断和兼容性不佳的问题&#xff0c;让很多升级w…

(附源码)springboot企业合同管理系统 毕业设计 161456

springboot企业合同管理系统 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对企业合同等问…

安装CUDA、anaconda、pytorch

文章目录前言一、CUDA安装1.查看CUDA版本2.安装CUDA2.1 下载CUDA2.2 安装CUDA2.3 测试CUDA安装成功二、anaconda安装1.anaconda下载2.anaconda环境变量配置3.测试anaconda安装成功3.anaconda常见命令操作3.1 清华镜像3.2 切换虚拟环境三、pytorch安装1.anaconda下pytorch安装2.…

YOLOV5模型转onnx并推理

YOLOV5模型转onnx并推理模型转onnx普通模型转onnxyolov5模型转onnxonnx 推理普通模型yolov5模型一、推理二、坐标转换三、非极大值抑制四、根据置信度过滤无用框五、画图六、总代码模型转onnx 普通模型转onnx 加载模型&#xff0c;需要是torch.save保存的模型指定输入输出的名…

模板建立

模板建立 步骤如果还没有建立一个组存储自己的模板,则先选择2(红框处)然后取个名字就好如果已经有组了,在自己建立的组内添加新模板1:后续快速生成使用的代码 2:对该模板的描述 3.模板代码 4.应该是为这个模版声明对应的语言(后附展示具体界面)根据需要选择语言,一般为java,也有…

JMeter详细安装教程

文章目录1 运行环境配置2 JMeter下载3 JMeter环境变量配置与启动3.1 环境变量配置3.2 启动1 运行环境配置 JMeter运行需要java环境&#xff0c;安装JMeter前需要安装配置好Java&#xff0c;参考文章Java环境变量配置详细教程 2 JMeter下载 下载地址&#xff1a;http://jmete…

新一期智能钱包系列:Louis Guthmann和 Ivo Georgiev 讨论账户抽象与智能钱包

Ambire 的 Twitter Space 第 10 集探讨了 EVM 生态系统中的互操作性和资产管理的解决方案。 &#x1f525;&#x1f525;准备好迎接第&#x1f51f;集了吗&#xff1f; 我们将对以太坊账户和智能合约进行研究&#x1f913;&#xff0c;这将会很有趣。&#x1f606; 周四凌晨 1 …

【Spring】AOP的三种方式

什么是aop AOP&#xff08;Aspect Oriented Programming&#xff09;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是Spring框架中的一个重要内…

SLAM第11讲

在&#xff11;&#xff11;讲中要下载DBow3库 地址&#xff1a;https://github.com/rmsalinas/DBow3 cd DBoW3 #进入源文件夹 mkdir build #新建一个编译目标文件夹 cd build #将build作为make工作路径 cmake -DUSE_CONTRIBON .. #编译上一级目录&#xff0c…

uni-app 怎么实现路由拦截

前言 随着业务的需求&#xff0c;项目需要支持H5、各类小程序以及IOS和Android&#xff0c;这就需要涉及到跨端技术&#xff0c;不然每一端都开发一套&#xff0c;人力成本和维护成本太高了。团队的技术栈主要以Vue为主&#xff0c;最终的选型是以uni-appuview2.0作为跨端技术…

Hugging Face学习

huggingface学习了解案列基础中文文本分类任务中文文本填空中文关系推断了解 Huggingface官网: link。Huggingface是一个开源社区&#xff0c;它提供给了先进的NLP模型&#xff0c;数据集以及其他的工具&#xff1a;数据集&#xff0c;数据集的下载地址&#xff1b;各种预训练…