【C语言】“qsort函数详解”与“使用冒泡思想模拟使用qsort”

简介: qsort的介绍:qsort ()函数是 C 库中实现的快速排序算法,包含在 stdlib.h 头文件中此函数需要四个参数void qsort(void* *base, size_t nitems, size_t size, int (compar)(const void * , const void))char* base —— 指向要排序的数组首元素地址的指针size_t nitems —— 要排序数组的元素个数size_t size —— 数组每个元素大的小 (有非常重要的作用)int compar(const void *,const void *) —— 由使用者提供的一

qsort的介绍:

qsort ()函数是 C 库中实现的快速排序算法,包含在 stdlib.h 头文件中

此函数需要四个参数void qsort(void* *base, size_t nitems, size_t size, int (compar)(const void * , const void))

char* base —— 指向要排序的数组首元素地址的指针

size_t nitems —— 要排序数组的元素个数

size_t size —— 数组每个元素大的小 (有非常重要的作用)

int compar(const void *,const void *) —— 由使用者提供的一个比较两个元素的函数

有两个参数,如果参数1大于参数2返回>0的数

参数1等于参数2返回0

参数1小于参数2返回<0的数

使用void*当作参数类型是因为此函数是一个回调函数,我们并不知道使用函数的人要比较哪两种数据,所有把参数设置成void *让使用者可以比较任意一种数据。(详细见下面配上代码分解:使用冒牌排序思想模拟实现qsort)

3.此函数无返回值

一、qsort函数的使用✨

  • 比较int类型数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void *arr1,const void *arr2)//提供按照int比较函数,如果参数1大于参数2返回>0的数,参数1等于参数2返回0,参数1小于参数2返回<0的数
{
  return *(int *)arr1 - *(int*)arr2;
}
int main()
{
  int arr[10] = { 4,3,5,6,7,8,1,2,9,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int width = sizeof(arr[0]);
  qsort(arr, sz, width, cmp_int);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);   //0 1 2 3 4 5 6 7 8 9 
  }
  printf("\n");
}
  • 比较字符型数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmp_char(const void* str1,const void* str2)     //提供按照字符比较函数,如果参数1大于参数2返回>0的数,参数1等于参数2返回0,参数1小于参数2返回<0的数
{
  return *(char*)str1 - *(char*)str2;
}
int main()
{
  char str[10] = { 'g','c','b','d','f','e','a' };
  int len = strlen(str);
  int width2 =  sizeof(str[0]);
  qsort(str, len, width2, cmp_char);
  printf("%s", str);        //abcdefg
  printf("\n");
}
  • 比较结构体数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct a 
{
  char name[10];
  int age;
};
int cmp_stru_a_name(const void * arr3,const void *arr4)   //按照name排序比较方法
{
  return strcmp(((struct a*)arr3)->name ,((struct a*)arr4)->name);
}
int cmp_stru_a_age(const void* arr1, const void* arr2)    //按照age排序比较方法
{
  return ((struct a*)arr1)->age - ((struct a*)arr2)->age;
}
int main()
{
  struct a arr2[] = { {"baobao",2} ,{"aoligei",4}{"caomei",3}};
  int sz2 = sizeof(arr2)/sizeof(arr2[0]);
  int width3 = sizeof(arr2[0]);
  qsort(arr2, sz2, width3, cmp_stru_a_name);    //按照结构体中name排序
  for (int i = 0; i < sz2; i++)
  {
    printf("%s ", arr2[i].name);    
    printf("%d ", arr2[i].age);
  }
  printf("\n");         //aoligei 4 baobao 2 caomei 3
  qsort(arr2, sz2, width3, cmp_stru_a_age);   //按照结构体中age排序
  for (int i = 0; i < sz2; i++)
  {
    printf("%s ", arr2[i].name);
    printf("%d ", arr2[i].age);
  }               //baobao 2 caomei 3 aoligei 4
}

冒泡思想模拟实现qsort函数

qsort底层使用的是快速排序,我们使用冒泡排序思想模拟实现效果与qsort相同的函数

冒泡排序:每次把最大的一个数字交换到最后面

void swap(char* arr1, char* arr2,int width)
{
  for (int i = 0; i < width; i++)
  {
    char* temp = *arr1;
    *arr1 = *arr2;
    *arr2 = temp;
    arr1++;
    arr2++;
  }
}
int cmp_int(const void* arr1, const void* arr2)   //提供比较函数
{
  return *(int*)arr1 - *(int*)arr2;   
}
void  bubble_sort(void *base,size_t sz,size_t width,int (*cmp)(const void*,const void*))
{
  for (int i = 0; i < sz - 1; i++)
  {
    for (int j = 0; j < sz - i - 1; j++)
    {
      if (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0) 
             //由于设计bubble_sort函数的时候我们还不知道使用者想比较什么类型的数据,所有可以把base强制转换成字符型指针再乘上元素宽度进行比较,使得无论传入的是什么类型的数据都可以比较。
      {
        swap((char*)base+j*width,(char*)base+(j+1)*width,width);
                //使用swap交换的时候也是如此,我们设计bubble_sort函数的时候不知道要对多少个字节进行交换,所以用把base强转成char*和宽度一起传入swap中,一个字节一个字节的进行交换
------
## 
      }
    }
  }
}
int main()
{
  int arr[10] = { 3,1,2,4,5,9,7,6,8,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int width = sizeof(arr[0]);
  bubble_sort(arr, sz, width, cmp_int);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);    //打印结果:0 1 2 3 4 5 6 7 8 9
  }
}

由于设计bubble_sort函数的时候我们还不知道使用者想比较什么类型的数据,所有可以把base强制转换成字符型指针再乘上元素宽度进行比较,使得无论传入的是什么类型的数据都可以比较。


使用swap交换的时候也是如此,我们设计bubble_sort函数的时候不知道要对多少个字节进行交换,所以用把base强转成char*和宽度一起传入swap中,一个字节一个字节的进行交换

拿int类型举例

e11ac7fcfd8243e58689384855eeb562.png

完结

创作不易,还请各位小伙伴多多点赞👍关注✨收藏⭐



d89241b7267e47efa46e331647af0e19.gif


























相关文章
|
2天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
26 15
|
2天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
39 24
|
2天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
39 23
|
1天前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
15 1
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
75 10
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
59 9
|
1月前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
55 6
|
1月前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
45 8
|
1月前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
318 6
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
69 6