qsort函数简介,qsort具体使用举例,冒泡排序模拟实现qsort

一、qsort函数简介

1.'qsort'函数是C标准库中用于对数组进行排序的函数。使用快速排序算法(quicksort)算法,这是一种高效的排序算法。

2.可以对任意类型的数据进行排序,因为它使用了比较函数指针来决定元素的相对顺序。

3.它声明在<stdlib.h>头文件中。

4.函数原型

void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void*,const void*) );

(1)'base':指向要排序的数组的其实地址

(2)'nmemb' :数组中元素的个数

(3)'size':每个元素的大小(以字节为单位)

(4)'compar':比较函数,用于确定两个元素的相对顺序

5.比较函数

比较函数需要比较两个元素,并返回一个整数

(1)第一个元素<第二个元素,返回负值(<0)。

(2)第一个元素=第二个元素,返回0

(3)第一个元素>第二个元素,返回正值(>0)

二、qsort函数具体使用举例

1.对'int'类型排序

#include<stdio.h>
#include<stdlib.h>
//比较函数:比较两个整数
int compare_ints(const void* a, const void* b)
{
	int int_a = *(int*)a;
	int int_b = *(int*)b;
	return (int_a > int_b) - (int_a < int_b);
}

int main()
{
	int arr[] = { 4,2,3,1,5 };
    //计算数组中元素的个数
	size_t arr_size = sizeof(arr) / sizeof(arr[0]);
	//调用qsort进行排序
	qsort(arr, arr_size, sizeof(int), compare_ints);
	//打印排序后的数组
	for (int i = 0; i < arr_size; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

(1)运行结果:           

(2)代码解释:

int compare_ints(const void *a, const void *b);

①'const void *a':指向第一个比较的元素。使用'const'表示该函数不会修改这个指针指向的内容。

②'const void *b':指向第二个比较的元素。使用'const'表示该函数不会修改这个指针指向的内容。

int int_a = *(int*)a;
int int_b = *(int*)b;

①‘a’和‘b’是‘const void*’类型,因为‘qsort’是通用函数,可以用于任意类型的数据排序。需要将‘ void *’转换成‘int *’,然后解引用以获得实际的整数值。

②(int*)a将'void *'类型的'a'转换为'int * '类型。

③‘ *(int*)a ’解引用‘int *’指针,获取指向的的整数值,并赋值给int_a。

return (int_a > int_b) - (int_a < int_b);

①比较并返回结果:这个表达式使用了布尔值计算:
(int_a > int_b)会产生一个布尔值,如果int_a大于int_b,结果是1,否则是0。
(int_a < int_b)会产生一个布尔值,如果int_a小于int_b,结果是1,否则是0。
    

②通过减法(int_a > int_b) - (int_a < int_b),可以得到:
    如果int_a大于int_b,结果是1 - 0 = 1(正值)。
    如果int_a等于int_b,结果是0 - 0 = 0(零)。
    如果int_a小于int_b,结果是0 - 1 = -1(负值)。

注意:(int_a > int_b) - (int_a < int_b)该表达式按升序排列,若按降序排列,则为(int_a < int_b)-(int_a > int_b)

2.对'char'类型排序

#include <stdio.h>
#include <stdlib.h>

// 比较函数:比较两个字符
int compare_chars(const void* a, const void* b) {
    char char_a = *(char*)a;
    char char_b = *(char*)b;
    return (char_a > char_b) - (char_a < char_b);
}

int main() {
    char arr[] = { 'd', 'b', 'a', 'c', 'e' };
    size_t arr_size = sizeof(arr) / sizeof(arr[0]);

    // 调用 qsort 进行排序
    qsort(arr, arr_size, sizeof(char), compare_chars);

    // 打印排序后的数组
    for (size_t i = 0; i < arr_size; i++) {
        printf("%c ", arr[i]);
    }
    printf("\n");

    return 0;
}

运行结果 :                                 

代码解释:
(1)compare_chars函数:将void指针转换为char指针并解引用,返回两个字符的差值。
(2)main函数:定义字符数组arr,计算数组大小,调用qsort进行排序,最后打印排序后的数组。

3.对结构体类型排序

#include <stdio.h>
#include <stdlib.h>

// 定义一个结构体类型
typedef struct {
    int id;
    float score;
} Student;

// 比较函数:比较两个结构体,根据分数排序
int compare_students(const void* a, const void* b) {
    Student student_a = *(Student*)a;
    Student student_b = *(Student*)b;
    return (student_a.score > student_b.score) - (student_a.score < student_b.score);
}

int main() {
    Student students[] = {
        {1, 85.5},
        {2, 90.0},
        {3, 78.0},
        {4, 92.0},
        {5, 88.5}
    };
    size_t arr_size = sizeof(students) / sizeof(students[0]);

    // 调用 qsort 进行排序
    qsort(students, arr_size, sizeof(Student), compare_students);

    // 打印排序后的结构体数组
    for (size_t i = 0; i < arr_size; i++) {
        printf("ID: %d, Score: %.1f\n", students[i].id, students[i].score);
    }

    return 0;
}

运行结果:                            

代码解释:
(1)定义结构体Student,包含id和score两个成员。
(2)compare_students函数:将void指针转换为Student指针并解引用,返回两个学生分数的差值。
(3)main函数:定义学生结构体数组students,计算数组大小,调用qsort进行排序,最后打印排序后的结构体数组。

通过这些示例,可以看到qsort函数如何在C语言中对不同类型的数据进行排序。关键在于提供适当的比较函数来比较数组中的元素。

三、冒泡排序模拟实现qsort

#include<stdio.h>
#include<stdlib.h>

//比较函数指针类型
typedef int (*compare_fun)(const void*, const void*);

//比较函数,比较两个整数
int compare_ints(const void* a, const void* b)
{
	int int_a = *(int*)a;
	int int_b = *(int*)b;
	return (int_a > int_b) - (int_a < int_b);
}

//冒泡排序函数:对数组进行排序(模拟qsort)
void bubble_sort(void* base, size_t nmemb, size_t size, compare_fun compare)
{
	char* arr = (char*)base;//将void指针转换为char指针以逐字节操作
	int i = 0;
	for ( i = 0; i < nmemb - 1; i++)//趟数
	{
		//一趟内部两两比较
		int j = 0;
		for (j = 0; j < nmemb - 1 - i; j++)
		{
			char* current = arr + j * size;//指向当前元素
			char* next = arr + (j + 1) * size;//指向下一个元素
			if (compare(current, next) > 0)
			{
				int k = 0;
				for (k = 0; k < size; k++)
				{
					char temp = *(current + k);
					*(current + k) = *(next + k);
					*(next + k) = temp;
				}
			}
		}

	}

}
int main()
{
	int arr[] = { 4,2,5,3,1 };
	size_t arr_size = sizeof(arr) / sizeof(arr[0]);
	//使用冒泡发模拟qsort进行排序
	bubble_sort(arr, arr_size, sizeof(int), compare_ints);
	//打印排序后的数组
	int i = 0;
	for (i = 0; i < arr_size; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

代码逻辑梳理:

1. 定义比较函数指针类型 `compare_func` :
`compare_func` 是一个函数指针类型,它指向一个函数,该函数接受两个 `const void* ` 类型的参数,并返回一个整数值。

2. 定义具体的比较函数 `compare_ints` :
`compare_ints` 是一个比较函数,用于比较两个整数。
它满足了 `compare_func` 函数指针类型的要求,接受两个 `const void* ` 类型的参数,并返回一个整数值。

3.定义冒泡排序函数 `bubble_sort` :
(1)`bubble_sort` 函数接受四个参数:数组的起始地址 `base`,数组中元素的个数 `nmemb`,每个元素的大小 `size`,以及一个比较函数指针 `compare`。
(2) 在函数内部,使用冒泡排序算法对数组进行排序。
(3) 每次比较两个元素时,使用 `compare` 函数指针来确定它们的相对顺序。

4. 在 `main` 函数中调用 `bubble_sort` :
(1) 在 `main` 函数中,定义了一个整数数组 `arr`,并计算了数组的大小 `arr_size`。
(2) 调用 `bubble_sort` 函数,将数组 `arr` 的起始地址、数组大小、每个元素的大小和比较函数指针 `compare_ints` 作为参数传递给了 `bubble_sort` 函数。

5. 冒泡排序实现 :
在 `bubble_sort` 函数内部,使用了冒泡排序算法对数组进行排序。每次迭代中,比较相邻的两个元素,根据比较函数指针 `compare` 确定它们的相对顺序,并在需要时交换它们的位置,直到数组完全排序。

6. 打印排序后的数组 :
最后,在 `main` 函数中,通过循环遍历打印了排序后的数组。

通过这个实现,我们实现了一个通用的冒泡排序函数 `bubble_sort`,它可以接受不同类型的比较函数,并对数组进行排序。

解释:!!

   在C语言中,函数名实际上就是函数的地址。当我们使用函数名时,编译器会自动将其转换为函数的地址。这意味着我们可以像传递其他变量一样,将函数名作为参数传递给函数。在这种情况下,我们可以将compare_ints函数名作为参数传递给bubble_sort函数。

   在bubble_sort函数的参数列表中,compare参数是一个函数指针,它指向一个函数,该函数接受两个const void* 类型的参数,并返回一个整数值。在bubble_sort函数内部,我们使用compare指针来调用这个函数,而不必知道它具体是哪个函数,只需知道它具有与compare_func类型一致的格式即可。

  因此,当我们在main函数中调用bubble_sort时,将compare_ints函数名作为参数传递给bubble_sort的compare参数时,实际上是将compare_ints函数的地址传递给了bubble_sort函数,因为函数名本身就代表着函数的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值