qsort()如此强大

本文介绍了C语言中使用标准库函数qsort()进行数组排序的方法,并提供了字符数组、整型数组及多关键字排序的实例代码。通过不同比较函数的应用,展示了如何灵活地对不同类型的数据进行排序。

这是一个排序的函数,包含在头文件#include<stdlib.h>中。因为排序在我们的编程中经常使用到,然而除了研究排序算法的时候我们会自己实现排序算法。在我们平时编程,如果没有特别的要求,我们还是使用标准库中写好的函数,既是出于编码效率的问题,我们也是为了代码运行的效率。当然在特定的时候我们需要自己实现特定要求的排序代码,但是不要急,我们先见识见识标准库排序函数的强大,到后面我们会专门讨论和研究排序算法的。

首先我们一起认识一下这个函数吧,下面是qsort()的函数原型

void qsort( 
  void* base, 
 size_t num, 
   size_t width, 
   int (
      __cdecl* compare 
   )(
      const void* elem1, 
          const void* elem2 
   ) 
);
函数参数说明:
base 
Start of target array. 
num 
Array size in elements. 
width 
Element size in bytes. 
compare 
Comparison function. 
elem1 
Pointer to the key for the search. 
elem2 
Pointer to the array element to be compared with the key. 
没有返回值。(参考MSDN)

下面我们直接进入我们的议题吧,利用qsort()排序。

l情景1:对字符数组和整形数组排序或比较字符串

如输入,3 2 4 1 5排序后输出??

如输入,b d s f g排序后输出??

如输入,abc abd dfgk kjljl 排序后输出??

#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
//比较两个字符的大小
int Comp_char(const void *a, const void *b)
{
	return *((char *)a) - *((char *)b);
}
//比较两个整数的大小
int Comp_int(const void *a, const void *b)
{
	return *((int *)b) - *((int *)b);
}
//比较两个字符串的大小
int Comp_str(const void *a, const void *b)
{
	return strcmp((char *)a, (char *)b);
}
//这里只给字符排序作为例子,我们已经给出了数值比较函数和字符串比较函数
//只要其他排序应用只要相应改变qsort( )函数的参数即可。
int main()
{
	char arr[20];
	int i = 0,j = 0;
	int m,n;
	cin>>n;
	while (i<n)
	{
		j = 0;
		cin>>m;
		//输入测试用例,存放在数组中
		while(j<m)
		{
			cin>>arr[j];
			++ j;
		}

		//利用qsort()给arr排序
		qsort(arr, m, sizeof(char), Comp_char);

		//输出排序后的结果
		j = 0;
		while (j<m)
		{
			cout<<arr[j]<<" ";
			++ j;
		}
		cout<<endl;
		++ i;
	}
	return 0;
}

->课后思考???

如果把Comp_char()改成下面这样子,输出又是什么?

int Comp_char(constvoid *a, const void *b)
{
      return *((char*)b) - *((char *)a);
}

情景二,多关键字排序

题目内容:

我们C语言协会实验室有很多的六面体,且长x,宽y,高z已知,我们现在要按下面的规则将他们排序,两个六面体a和b。如果a的长x比b的长x大,那么a排在b的前面,如果a的x和b的x相同,那么在比较他们的宽y,谁大谁排在前面,如果他们的宽也相同,那么比较他们的高z。我们假设没有任何相同大小的六面体。现在我们希望你对实验室这么多的六面体排序

输入描述:

先输入n,表示测试数据的组数,在输入m,代表六面体的个数,随后的n行分别为每个六面体的长,宽,高。

输出描述:

输出六面体排序后的顺序

输入样例:

1

3

1 2 3

2 3 1

1 3 2

输出样例:

2 3 1

1 3 2

1 2 3

应对策略:

我们只需要改变我们的Comprion函数即可,将我们比较的规则在Comprion函数实现即可,和我们上面几乎没有什么区别
C语言版:
#include<iostream>
#include<cstdlib>
using namespace std;
//六面体节点
struct Node{
	int x; //长
	int y; //宽
	int z; //高
};
int Comp_node(const void *a, const void *b)
{
	struct Node *node_a = (struct Node *)a;
	struct Node *node_b = (struct Node *)b;

	if (node_a->x != node_b->x)
	{
		return (node_b->x - node_a->x);
	}
	if (node_a->y != node_b->y)
	{
		return (node_b->y - node_a->y);
	}
	return (node_b->z - node_a->z);
}
int main()
{
	int m,n;
	int i = 0,j = 0;
	struct Node node_arr[20];

	cin>>n;
	while (i<n)
	{
		cin>>m;
		//输入m个六面体的长宽高
		j = 0;          //记得重新赋值为零
		while (j<m)
		{
			cin>>node_arr[j].x>>node_arr[j].y>>node_arr[j].z;
			++ j;
		}

		qsort(node_arr, m, sizeof(struct Node), Comp_node);
		//输出排好序的结果
		j = 0; 		     //记得重新赋值为零
		while (j<m)
		{
			cout<<node_arr[j].x<<" "<<node_arr[j].y<<" "<<node_arr[j].z<<endl;
			++ j;
		}
		cout<<endl;
		++ i;
	}
	return 0;
}





09-06
<think> 我们被要求回答关于qsort函数的使用方法和原理,并且参考了提供的引用材料。根据引用[1]到[5],我们可以总结如下: 1. qsort函数是C语言标准库中的一个排序函数,位于stdlib.h头文件中。 2. qsort函数的原理是快速排序,时间复杂度为O(n log n)。 3. qsort可以排序任意类型的数组(整型、字符型、结构体等),因为它是通过指针操作和用户自定义的比较函数来实现的。 引用中提供了qsort函数的原型以及使用示例。下面我们详细介绍: ### qsort函数原型 ```c void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); ``` 参数说明: - `base`:指向待排序数组的第一个元素的指针(数组的起始地址)。 - `nmemb`:数组中元素的个数。 - `size`:数组中每个元素的大小(以字节为单位)。 - `compar`:比较函数的指针,该函数用于定义两个元素如何进行比较。 ### 比较函数 比较函数的形式为: ```c int compar(const void *a, const void *b); ``` 该函数需要返回一个整数,表示两个元素的比较结果: - 如果返回值小于0,表示a应该排在b前面(升序时a<b)。 - 如果返回值等于0,表示a和b相等。 - 如果返回值大于0,表示a应该排在b后面(升序时a>b)。 注意:通过改变比较函数中的比较方式(例如,将a和b的位置调换),可以实现升序或降序排列。 ### 使用步骤 1. 包含头文件`#include <stdlib.h>`。 2. 定义比较函数,根据要排序的数据类型和排序顺序编写。 3. 调用qsort函数,传入数组、元素个数、元素大小和比较函数。 ### 示例 以下是一个对整型数组进行升序排序的示例(参考引用[4]): ```c #include <stdio.h> #include <stdlib.h> // 比较函数:升序 int cmp_int(const void *p1, const void *p2) { return (*(int*)p1 - *(int*)p2); } int main() { int arr[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10}; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(int), cmp_int); // 打印数组 for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; } ``` ### 原理 qsort函数的内部实现基于快速排序算法。快速排序是一种分治的排序算法: 1. 选择一个基准元素(pivot)。 2. 将数组分为两部分,使得左边部分的元素都小于或等于基准,右边部分都大于或等于基准。 3. 递归地对左右两部分进行快速排序。 由于qsort的实现可能根据不同的环境有所优化,但核心是快速排序。引用[2]提到其时间复杂度为O(n log n)。 ### 注意事项 - 比较函数中,必须将void指针转换为实际数据类型的指针,然后再解引用进行比较。 - 对于结构体等自定义类型,需要根据具体的成员进行比较。 例如,对一个结构体数组按某个成员排序: ```c typedef struct { char name[20]; int age; } Person; int cmp_person_age(const void *a, const void *b) { Person *pa = (Person*)a; Person *pb = (Person*)b; return pa->age - pb->age; // 按年龄升序 } ``` ### 总结 qsort函数是C语言中一个通用的排序函数,通过快速排序算法实现,支持任意数据类型的排序。使用关键在于正确编写比较函数。 §§相关问题§§ 1. qsort函数在排序过程中是否稳定? 2. 如何用qsort对字符串数组进行排序? 3. qsort函数在什么情况下会退化为O(n^2)的时间复杂度? </think> ### qsort函数详解 #### 🧩 一、qsort函数原理 1. **算法基础**: qsort采用**快速排序算法**(Quick Sort),平均时间复杂度为$O(n \log n)$,最坏情况(如已排序数组)退化为$O(n^2)$[^2][^5]。 2. **通用设计**: 通过`void*`指针实现泛型编程,可排序任意数据类型(整型、字符、结构体等)。核心原理: - **元素交换**:根据`size`参数计算内存偏移量,逐字节交换数据。 - **比较逻辑**:依赖用户自定义的**比较函数**(函数指针)决定排序规则[^2][^5]。 --- #### 📝 二、使用方法 ##### 函数原型 ```c void qsort(void *base, // 数组首地址 size_t nmemb, // 元素数量 size_t size, // 单个元素大小(字节) int (*compar)(const void*, const void*) // 比较函数 ); ``` ##### 关键步骤 1. **定义比较函数**: ```c int compar(const void *p1, const void *p2) { // 升序:*(目标类型*)p1 - *(目标类型*)p2 // 降序:*(目标类型*)p2 - *(目标类型*)p1 } ``` - 返回值规则: - **<0**:`p1`排在`p2`前 - **=0**:相对位置不变 - **>0**:`p1`排在`p2`后[^5] 2. **调用qsort**: ```c int arr[5] = {3, 1, 4, 2, 5}; size_t nmemb = sizeof(arr)/sizeof(arr[0]); qsort(arr, nmemb, sizeof(int), compar_int); ``` --- #### 三、应用示例 ##### 1. 整型数组升序排序 ```c #include <stdlib.h> #include <stdio.h> int cmp_int(const void* p1, const void* p2) { return (*(int*)p1 - *(int*)p2); // 升序 // return (*(int*)p2 - *(int*)p1); // 降序 } int main() { int arr[] = {5, 2, 8, 1, 6}; size_t sz = sizeof(arr)/sizeof(arr[0]); qsort(arr, sz, sizeof(int), cmp_int); // 输出:1 2 5 6 8 } ``` ##### 2. 结构体按字段排序 ```c typedef struct { char name[20]; int age; } Person; int cmp_age(const void* p1, const void* p2) { return ((Person*)p1)->age - ((Person*)p2)->age; } int main() { Person people[3] = {{"Alice", 25}, {"Bob", 20}, {"Charlie", 22}}; qsort(people, 3, sizeof(Person), cmp_age); // 按年龄升序:Bob(20) -> Charlie(22) -> Alice(25) } ``` --- #### ️ 四、注意事项 1. **内存安全**: 比较函数中需确保指针转换正确,避免未定义行为。 2. **稳定性**: 快速排序**不稳定**,相同元素可能改变相对顺序。 3. **效率优化**: 对小数组可改用插入排序避免快速排序递归开销[^2]。 --- #### 💡 五、模拟实现原理(伪代码) ```c void swap(char* a, char* b, size_t size) { // 逐字节交换两个元素 for(size_t i=0; i<size; i++) { char tmp = a[i]; a[i] = b[i]; b[i] = tmp; } } void qsort_impl(void* base, size_t nmemb, size_t size, int (*cmp)(const void*, const void*)) { if(nmemb <= 1) return; char* pivot = (char*)base; char* left = (char*)base + size; char* right = (char*)base + (nmemb-1)*size; while(left <= right) { while(cmp(left, pivot) < 0) left += size; while(cmp(right, pivot) > 0) right -= size; if(left <= right) { swap(left, right, size); left += size; right -= size; } } // 递归排序左右分区 size_t left_size = (right - (char*)base) / size + 1; qsort_impl(base, left_size, size, cmp); qsort_impl(left, nmemb - left_size, size, cmp); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值