• qsort使用举例和qsort函数的模拟实现


    qsort使用举例

    qsort是C语言中的一个标准库函数,用于对数组或者其他数据结构中的元素进行排序。它的原型如下:
    void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

    我们可以去官网搜来看一看:

    那么对于其中的参数,下面也有相应的英文解释:

    - base:指向要排序的数组或数据结构的第一个元素的指针。
    - nmemb:要排序的元素的数量。
    - size:每个元素的大小(以字节为单位)。
    - compar:指向用于比较两个元素的函数的指针。

    compar函数用于比较两个元素的大小关系,返回值为整数,表示两个元素的大小关系。具体返回值的含义如下:
    - 若返回值小于0,则表示第一个元素小于第二个元素。
    - 若返回值等于0,则表示两个元素相等。
    - 若返回值大于0,则表示第一个元素大于第二个元素。

    qsort函数根据compar函数的返回值对数组或数据结构中的元素进行排序,可以按照升序或降序进行排序。
    那么知道以上这些,下面我们就来使用这个库函数,首先我们以排序整型数组为例:

    int arr[10] = { 4,5,7,6,3,2,8,9,1,10 };

    假设我们要排列以上的10个元素,那么我们根据上面对于库函数qsort的认识,需要向它传入四个参数,那么第一个为- base:指向要排序的数组或数据结构的第一个元素的指针,那么就是我们的arr 了,第二个为- nmemb:要排序的元素的数量,这是我们就要计算里面有多少个元素了,我们可以这样算:

    int sz = sizeof(arr) / sizeof(arr[0]);

    使用第二个参数我们可以写为  sz ,第三个为- size:每个元素的大小,那么我们计算出数组中第一个元素有多少个字节就可以了 sizeof(arr[0]),最后一个为- compar:指向用于比较两个元素的函数的指针,这里我们就需要我们自己写一个函数了,告诉这个库函数qsort我们要比较什么类型的数据:

    qsort(arr, sz, sizeof(arr[0]), cop_int);

    那么接下来就是这个cop_int函数怎么写了,因为我们不知道会传什么样的数据,所以我们可以使用void*进行接收,返回类型为int型,因为下面是根据大于或小于或等于来排序的,而且不希望改我们所要排序的数值,所以我们这样写到:

    int cop_int(const void* p1, const void* p2)

    上面传来了void*类型的数据,而void*的数据不能够直接进行运算操作,所以下面我们要进行强制类型转换,作差看看两数的情况:

    return *(int*)p1 - *(int*)p2;

    下面就来看看我们整体的代码:

    1. #include //头文件
    2. void Print_arr(int arr[], int sz)
    3. {
    4. for (int i = 0; i < sz; i++)
    5. {
    6. printf("%d ", arr[i]);
    7. }
    8. }
    9. int cop_int(const void* p1, const void* p2)
    10. {
    11. return *(int*)p1 - *(int*)p2;
    12. }
    13. int main()
    14. {
    15. int arr[10] = { 4,5,7,6,3,2,8,9,1,10 };
    16. int sz = sizeof(arr) / sizeof(arr[0]);
    17. qsort(arr, sz, sizeof(arr[0]), cop_int);
    18. Print_arr(arr, sz);
    19. return 0;
    20. }

    看看我们的运行效果:

     下面我们给结构体进行排序:

    我们先随便写一个结构体:

    1. struct Stu
    2. {
    3. char name[20];
    4. int age;
    5. int score;
    6. };//定义一个学生的名字,岁数,分数

    我们只需要改我们的- compar:指向用于比较两个元素的函数的指针,我们先以学生的名字进行排序,那么结构体我们只需要转换成结构体指针就可以进行比较了,名字我们strcmp进行比较:

    1. #include //qsort的头文件
    2. #include //strcmp的头文件
    3. struct Stu
    4. {
    5. char name[20];
    6. int age;
    7. int score;
    8. };
    9. int cop_Stu_by_name(const void* p1, const void* p2)
    10. {
    11. return strcmp(((struct Stu*)p1)->name , ((struct Stu*)p2)->name);
    12. }
    13. int main()
    14. {
    15. struct Stu arr[] = { {"zhangsan",18,76},{"lisi",28,65},{"wangmazi",25,79}};
    16. int sz = sizeof(arr) / sizeof(arr[0]);
    17. qsort(arr, sz, sizeof(arr[0]), cop_Stu_by_name);
    18. for (int i = 0; i < sz; i++)
    19. {
    20. printf("%s %d %d\n", arr[i].name, arr[i].age,arr[i].score);
    21. }
    22. return 0;
    23. }

    看看运行的结果:

     是正确的哦!我们还可以以年龄进行比较还有分数啊,这里我就不排了,我们下面用冒泡排序来qsort函数的模拟实现!

    qsort函数的模拟实现(采用冒泡排序法)

    对于冒泡排序,我在前面也写到过,还不太清楚的小伙伴可以看看哦。

    1. void BubbleSort(int arr[], int sz)
    2. {
    3. for (int i = 0; i < sz - 1; i++)//趟数
    4. {
    5. for (int j = 0; j < sz - 1 - i; j++)//一趟冒泡排序
    6. {
    7. if (arr[j] > arr[j + 1])//需要进行改造的地方 1
    8. {
    9. int tmp = arr[j];// 需要进行改造的地方 2
    10. arr[j] = arr[j + 1];
    11. arr[j + 1] = tmp;
    12. }
    13. }
    14. }
    15. }
    16. int main()
    17. {
    18. int arr[] = { 5,7,9,4,3,6,8,1 };//5 7 9 4 3 6 8 1
    19. int sz = sizeof(arr) / sizeof(arr[0]);//计算有多少个元素
    20. BubbleSort(arr, sz);
    21. for (int i = 0; i < sz; i++)
    22. {
    23. printf("%d ", arr[i]);
    24. }
    25. return 0;
    26. }

    首先我们先来想一想,那些地方需要我们改造,对于循环那些我们是不是就不用改了,那不会有影响。我们将会排序到不同的数据类型,所以我们对于 if (arr[j] > arr[j + 1])的比较,是不是需要我们进行改造呢,还有下面的交换变量,也是我们需要改的,既然上面的类型都被改了,下面也肯定是需要改的。

    我们以结构体的年龄为例,那么函数的参数还是我们上面的那样,只是要改一下第四个参数:

    bubble_sort2(arr, sz, sizeof(arr[0]), cop_Stu_by_age);

    接下来就是对于bubble_sort2函数的定义了,下面传了四个参数,那我们也要用四个参数进行接收了,因为我们不知道传来的是什么类型的,所以在设置类型上,我们要考虑考虑,第一个为地址,我们用void*进行接受吧,void*都装的了,哈哈。第二个和第三个就用size_t了,最后一个像我们上面考虑的那个样:int (*cmp)(const void* p1, const void* p2)。

    1. void bubble_sort2(void* base,size_t sz,size_t width, int (*cmp)(const void* p1, const void* p2))
    2. {
    3. for (int i = 0; i < sz-1; i++)
    4. {
    5. for (int j = 0; j < sz-1-i; j++)
    6. {
    7. if (arr[j] > arr[j + 1])
    8. {
    9. int tmp = arr[j];
    10. arr[j] = arr[j + 1];
    11. arr[j + 1] = tmp;
    12. }
    13. }
    14. }
    15. }

    接着就是对于比较的改造了,我们这里构造一个新的函数进行比较,这样我们根据下面传来的类型去调用相应的,那么我们怎样找到我们的对应的元素进行比较呢?下面给给了我们首元素的地址,和每个元素的大小,我们是不是可以用起来呢,我们根据j的变化去找到元素。但是还要想到我们要用它来不同数据类型的排序,所以我们也要进行强制类型转换。我们强制转换成什么类型的数据呢?是不是char*最为合适呢,不管是什么类型,我们都可以一个一个的去进行交换:

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

    下面我们进行对于交换的改造:上面改成了那样,所以接收时也改成相应的就行了,我们以前进行交换的时候是创建了第三个变量进行交换,现在我们不知什么类型,就需要改进了。强制转换成什么类型比较合适呢?假设我们结构体的为7个字节大小,那我们是不是用char类型就可以了,不管你如何,我一个一个的进行交换就都可以实现,既然我们以这样的方式进行实现,那我们是不是应该把它每个元素的大小传进来呢:

    1. void swap(char* a, char* b, size_t width)
    2. {
    3. for (int i = 0; i < width; i++)
    4. {
    5. char tmp = *a;
    6. *a = *b;
    7. *b = tmp;
    8. a++;
    9. b++;
    10. }
    11. }

    接下来我们就看看整体的代码:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. struct Stu
    4. {
    5. char name[20];
    6. int age;
    7. };
    8. int cop_Stu_by_age(const void* p1, const void* p2)
    9. {
    10. return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
    11. }
    12. int cop_int(const void* p1, const void* p2)
    13. {
    14. return *(int*)p1 - *(int*)p2;
    15. }
    16. void PrintArr(int arr[], int sz)
    17. {
    18. for (int i = 0; i < sz; i++)
    19. {
    20. printf("%d ", arr[i]);
    21. }
    22. }
    23. void swap(char* a, char* b, size_t width)
    24. {
    25. for (int i = 0; i < width; i++)
    26. {
    27. char tmp = *a;
    28. *a = *b;
    29. *b = tmp;
    30. a++;
    31. b++;
    32. }
    33. }
    34. //冒泡排序
    35. void bubble_sort2(void* base,size_t sz,size_t width, int (*cmp)(const void* p1, const void* p2))
    36. {
    37. for (int i = 0; i < sz-1; i++)
    38. {
    39. for (int j = 0; j < sz-1-i; j++)
    40. {
    41. //if (arr[j] > arr[j + 1])
    42. if(cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
    43. {
    44. swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
    45. /*int tmp = arr[j];
    46. arr[j] = arr[j + 1];
    47. arr[j + 1] = tmp;*/
    48. }
    49. }
    50. }
    51. }
    52. int main()
    53. {
    54. struct Stu arr[] = { {"aihua",18},{"zhanghong",21},{"kiki",15} };
    55. int sz = sizeof(arr) / sizeof(arr[0]);
    56. //年龄
    57. bubble_sort2(arr, sz, sizeof(arr[0]), cop_Stu_by_age);
    58. for (int i = 0; i < sz; i++)
    59. {
    60. printf("%s %d\n", arr[i].name, arr[i].age);
    61. }
    62. return 0;
    63. }

    看看运行结果:

     那么也是可以的哟,我这里就是用其他类型进行排序了,感兴趣的话,可以去试试哦,本来还想着画图给你们梳理一下,可那个画图工具不给力😢😢😢!

    愿你们冬不寒!❤❤❤

  • 相关阅读:
    Java虚拟机
    【论文阅读】- 我对“AlexNet”的理解
    C++-Cmake指令:target_link_libraries
    【推送服务】【FAQ】Push Ki常见咨询合集7--其它问题
    Pycharm 2023 设置远程调试
    腾讯云服务器简介和使用流程
    【Linux C】Linux如何执行一个程序(程序存储空间、系统调用、内核调用)
    pointwise如何提升网格质量呢
    【证明】线性空间的基本性质
    神经元结构图简笔画,神经组织图片简笔画
  • 原文地址:https://blog.csdn.net/2302_77675796/article/details/134489122