C语言 您所在的位置:网站首页 快速排序的类型定义 C语言

C语言

2024-07-15 02:05| 来源: 网络整理| 查看: 265

一. 介绍 qsort 函数

我们以前学习过一些排序算法,如冒泡,选择,归并,快速排序等等,它们排序的速度有快有慢,但这些排序都只能排序一种类型的数据,如果想再排序另外一种类型得数据就需要再另写一个排序,所以有没有什么排序是万能的,既能排整形,又能排浮点型,还能排字符串类型等等的排序呢?

答案是有的,它就是 qsort 函数。

qsort 函数官方定义:

形式就是:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*)); // base -> 需要排序的数组的起始地址 // num -> 数组内元素的个数(数组的大小) // size -> 一个元素的大小(单位是字节) // int (*compar)(const void*,const void*) -> compar(一个函数指针),类型是 int (*)(const void*,const void*)

大家也都能了解,这个函数的重点就在于 compar 这一函数指针。

分析 compar 函数指针:

在排序时,比较整形,浮点型都可以使用大于,小于,等于号直接比较大小,比较字符串可以使用 strcmp 函数;但是若要比较结构体呢?结构体内含有多种数据类型,此时若要比较就得写出多个排序函数,但是在 qsort 函数内 ,有了 compar 函数指针这种问题就能轻易的被实现。

compar 函数指针:我们发现给它传递的是两个 const void* 类型的指针,返回的是 int 类型的数字,也看到官方的讲解(若传递 p1指针和 p2 指针)其返回的是 -1(*p1*p2)。

按照 compar 定义,数组是以升序的顺序进行排序的,但是若要以降序的顺序进行排序,则就将函数内部返回时的 p1 与 p2 进行颠倒。具体实现看以下实例。

二. qsort 函数使用方法

因为 qsort 函数是一个库函数,所以在使用时需要包含一个头文件 #include

在写好 qsort 函数内的变量时,需要再写一个 compar 指针函数所指向的函数。新函数内部的 p1 和 p2 一定要强制类型转换成要排序的数组的类型。

三. qsort 函数使用实例         1. qsort 函数排序整形 #include int smp_int(const void* p1, const void* p2) { // return (int)(*(int*)p1 - *(int*)p2); //->升序 return (int)(*(int*)p2 - *(int*)p1); //->降序 } int main() { int arr[] = { 2,4,1,6,8,4,9,3,7 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), smp_int); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }

我们发现:smp_int 函数内在返回时,都先将 p1 和 p2 两个指针强制类型转换成 int* 类型,再进行解引用操作,再相减。因为此函数最终返回的结果是 int 类型,所以最后再将得出的结果强制转化成 int 类型。 

        2. qsort 函数排序浮点型 #include int smp_double(const void* p1, const void* p2) { return (int)(*(double*)p1 - *(double*)p2); //升序 } int main() { double arr[] = { 2.3,4.7,1.1,6.5,8.8,4.9,9.2,43.5,7.77 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), smp_double); int i = 0; for (i = 0; i < sz; i++) { printf("%.2lf ", arr[i]); } return 0; }

此代码与 排序整形 有异曲同工之处。大家可试着分析。

        3. qsort 函数排序字符数组 #include int smp_char(const void* p1, const void* p2) { return (int)(*(char*)p1 - *(char*)p2); } int main() { char arr[] = { 'b','a','y','d','f'}; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), smp_char); int i = 0; for (i = 0; i < sz; i++) { printf("%c ", arr[i]); } return 0; }

 字符在排序时:'a'< 'b' < 'c' < ... < 'y' < 'z'。

        4. qsort 函数排序结构体 #include struct Book { char name[30]; // 书名 char author[20]; // 作者 double price; // 价钱 }; int smp_name(const void* p1, const void* p2) { return strcmp(((struct Book*)p1)->name, ((struct Book*)p2)->name); } void Print_name(struct Book* b1,int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%-30s\t%-20s\t%.1lf\n", b1[i].name, b1[i].author, b1[i].price); } } int main() { struct Book b1[] = { {"《C语言》","张三",49.9},{"《数据结构》","李四",59.9},{"《英语》","王五",12.8},{"《Python程序基础》","阿牛",47.8} }; int sz = sizeof(b1) / sizeof(b1[0]); qsort(b1, sz, sizeof(b1[0]), smp_name); Print_name(b1,sz); return 0; }

排序结构体分析:此代码先定义一个结构体(描述一些类型),在写 smp_name 代码时,需要将两个指针先转换为结构体类型的指针,比较什么数据,就让其指向什么数据,因为其比较的是字符串类型的数据,所以字符串的比较用的是 strcmp 函数。

四. 冒泡排序实现 qsort 函数

库函数内的qsort 函数实现是用快速排序写成的,但是为了大家更好的方便理解 qsort 函数这一实现过程,此处用冒泡排序实现 qsort 函数。

void Swap(char* buf1, char* buf2,int size) { char tmp = 0; int i = size; while (i--) { tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void my_qsort(void* base, size_t num, size_t size, int (*compar)(const void*, const void*)) { int i = 0; for (i = 0; i < num-1; i++) { int j = 0; for (j = 0; j < num - 1 - i; j++) { if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0) Swap((char*)base + j * size, (char*)base + (j + 1) * size,size); } } }

相信大家肯定对这两行代码有疑惑:

if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0) Swap((char*)base + j * size, (char*)base + (j + 1) * size,size);

 在分析之前,大家先看这张图片:

其代表了所有函数与函数之间的调用情况和联系(有助于大家理解)。 

分析代码:

        在实现 qsort 函数时,因为函数所接收来的数组是 void* 类型的,不知道元素具体是什么类型,无法使用下标来访问数组内的元素,故此只能将 base 强制转换成 char* 类型的,因为 char* 类型每次移动的字节数是一个字节,使用 char* 类型就能在保证不遗落字节的情况下,访问到数组空间内所有的字节,因为每两个元素之间相隔一个 size 大小字节的宽度,所以 用 (char*)base+j * size来取出第一个元素的地址,用 (char*) base+(j+1)*size 取出第二个元素的地址,然后将它们再放入到 smp_int 函数中进行比较。之后再依次取出之后元素的地址,再次比较。

int smp_int(const void* p1, const void* p2) { return (int)(*(int*)p1 - *(int*)p2); }

        比较之后,若两个元素需要交换时,因为事先并不知道元素是什么类型,所以还得用到 char* 类型来一个字节一个字节的进行交换。

void Swap(char* buf1, char* buf2,int size) { char tmp = 0; int i = size; while (i--) { tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } }

检测函数实现情况:

1. 检测整形 #include int smp_int(const void* p1, const void* p2) { return (int)(*(int*)p1 - *(int*)p2); } int main() { int arr[] = { 2,4,1,6,8,4,9,3,7 }; int sz = sizeof(arr) / sizeof(arr[0]); my_qsort(arr, sz, sizeof(arr[0]), smp_int); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }

运行结果:

2. 检测浮点型 #include int smp_double(const void* p1, const void* p2) { return (int)(*(double*)p1 - *(double*)p2); } int main() { double arr[] = { 2.3,4.7,1.1,6.5,8.8,4.9,9.2,43.5,7.77 }; int sz = sizeof(arr) / sizeof(arr[0]); my_qsort(arr, sz, sizeof(arr[0]), smp_double); int i = 0; for (i = 0; i < sz; i++) { printf("%.2lf ", arr[i]); } return 0; }

代码运行结果: 

3. 检测字符数组 #include int smp_char(const void* p1, const void* p2) { return (int)(*(char*)p1 - *(char*)p2); } int main() { char arr[] = { 'b','a','y','d','f' }; int sz = sizeof(arr) / sizeof(arr[0]); my_qsort(arr, sz, sizeof(arr[0]), smp_char); int i = 0; for (i = 0; i < sz; i++) { printf("%c ", arr[i]); } return 0; }

代码运行结果:

4. 检测结构体 #include struct Book { char name[30]; // 书名 char author[20]; // 作者 double price; // 价钱 }; int smp_author(const void* p1, const void* p2) { return strcmp(((struct Book*)p1)->author, ((struct Book*)p2)->author); } void Print_author(struct Book* b1, int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%-20s\t%-30s\t%.1lf\n", b1[i].author, b1[i].name, b1[i].price); } } int main() { struct Book b1[] = { {"《C语言》","张三",49.9},{"《数据结构》","李四",59.9},{"《英语》","王五",12.8},{"《Python程序基础》","阿牛",47.8} }; int sz = sizeof(b1) / sizeof(b1[0]); my_qsort(b1, sz, sizeof(b1[0]), smp_author); Print_author(b1, sz); return 0; }

代码运行结果:



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有