玩转qsort——“C”

简介: 玩转qsort——“C”

各位CSDN的uu们你们好呀,今天小雅兰的内容还是我们的深度剖析指针呀,上篇博客我们学习了回调函数这个知识点,但是没有写完,因为:小雅兰觉得qsort值得单独写出来!!!好啦,就让我们进入指针的世界吧


qsort是一个库函数,是用来排序的库函数,使用的是快速排序的方法


quicksort


我们先来复习一下之前所学习过的一种算法——冒泡排序


冒泡排序——“C”_认真学习的小雅兰.的博客-CSDN博客


#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz - 1; i++)
  {
    //一趟冒泡排序的过程
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
}
int main()
{
  int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
  //排序
  //使用冒泡排序的算法,来排序
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz);
  //打印
  print_arr(arr, sz);
  return 0;
}

abe2bdf7231347caa3371c3baa6da648.png

但是,这个算法最大的缺点就是只能排序整型,如果未来要排序浮点数呢?如果未来要排序一些字符串呢?结构体呢?那么,这个函数就搞不定了,仅仅能排序固定类型的数据


qsort的好处:


现成的

可以排序任意类型的数据

void qsort( void *base,//指向了待排序数组的第一个元素


                    size_t num,//待排序的元素个数


                    size_t width,//每个元素的大小,单位是字节


                    int (__cdecl *compare )(const void *elem1, const void *elem2 )


                    //函数指针


                    //指向一个函数,这个函数可以比较两个元素的大小


                  );


qsort是可以排序任意类型的数据的


比较两个整数的大小,>  <  =

比较两个字符串,strcmp

比较两个结构体数据(学生:张三、李四),指定比较的标准,拿什么比较?

int a=10;


void * p=&a;


//void * ——无具体类型的指针,所以它可以接收任何类型的地址


//*p;//err void*的指针不能使用解引用操作符


//p++;//err


下面,我们来使用一下qsort函数:

18dc062be3d24290ae398cf1834af240.png

#include<stdio.h>
#include<stdlib.h>
//qsort函数的使用者提供这个函数
int cmp_int(const void* p1, const void* p2)
{
  return *(int*)p1 - *(int*)p2;
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
test1()
{
  int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  //使用qsort来排序整型数组,这里就要提供一个比较函数,这个比较函数能够比较2个整数的大小
  //qsort默认是排成升序的
  qsort(arr, sz, sizeof(arr[0]), cmp_int);
  print_arr(arr, sz);
}
int main()
{
  test1();
  return 0;
}

e6443f90a4a44018a54af04834608d84.png

qsort这个库函数是不是很神奇呢?下面还有更加神奇的!!!

我们来测试一下qsort排序结构体数据

#include<stdio.h>
#include<stdlib.h>
//qsort函数的使用者提供这个函数
int cmp_int(const void* p1, const void* p2)
{
  return *(int*)p1 - *(int*)p2;
}
struct Stu
{
  char name[20];
  int age;
};
int cmp_stu_by_age(const void* p1, const void* p2)
{
  return ((struct  Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void print(struct Stu* ps, int sz)
{
  int i = 0;
  for (i = 0; i < 3; i++)
  {
    printf("%d\n", ps[i].age);
  }
}
void test2()
{
  struct Stu s[] = { {"zhangsan",30},{"lisi",25 }, { "wangwu",50 } };
    int sz = sizeof(s) / sizeof(s[0]);
  //测试按照年龄来排序
  qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
  print(s, sz);
}
int main()
{
  test2();
  return 0;
}

13c9bba3ff1b471eb2923b6df0f85ab7.png

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{
  char name[20];
  int age;
};
int cmp_stu_by_name(const void* p1, const void* p2)
{
  return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void print(struct Stu *ps, int sz)
{
  int i = 0;
  for (i = 0; i < 3; i++)
  {
    printf("%s\n", ps[i].name);
  }
}
void test2()
{
  struct Stu s[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };
  int sz = sizeof(s) / sizeof(s[0]);
  //测试按照名字来排序
  qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
  print(s, sz);
}
int main()
{
  test2();
  return 0;
}

ab2de0685af14cada43d83647b0b3af6.png

qsort底层是快速排序,但是小雅兰还没有学习快速排序的思想,所以暂时还不能之间实现qsort,所以使用冒泡排序的思想来实现一个类似于qsort这个功能的冒泡排序函数bubble_sort

使用回调函数,模拟实现qsort(采用冒泡的方式)。

测试函数:

void test3()
{
  int arr[] = { 3,1,5,2,4,9,8,6,7,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
  print_arr(arr, sz);
}

主函数:

int main()
{
  test3();
  return 0;
}

模拟实现的bubble_sort()函数:

//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2))
{
  //base 待排序数组的第一个元素
  //元素个数和元素个数的大小不可能是负数,所以是size_t类型
  //函数指针
  //要确定趟数
  size_t i = 0;
  for (i = 0; i < num - 1; i++)
  {
    //一趟冒泡排序的过程
    size_t j = 0;
    int flag = 1;//假设已经有序了
    //标记变量
    for (j = 0; j < num - 1 - i ; j++)
    {
      //两个相邻的元素比较
      //arr[j] arr[j+1]
      if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
      {
        //强制类型转换为char*
        //因为base为void类型,不能之间进行加减乘除,所以强制类型转换,但是又不能转换为int*,因为不一定就排序整型数组
        flag = 0;
        //交换
        Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
      }
    }
    if (flag == 1)
    {
      break;
    }
  }
}

在bubble_sort()函数中,调用了自定义的函数Swap,是用来交换元素的:

int cmp_int(const void* p1, const void* p2)//不知道要排序什么类型的数组,所以用void*
{
  return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1, char* buf2,int width)
{
  int i = 0;
  for (i = 0; i < width; i++)
  {
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
  }
}

打印函数:

void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}

482cf4a445204efa89e92a974e5a8c1a.png

完整代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int cmp_int(const void* p1, const void* p2)//不知道要排序什么类型的数组,所以用void*
{
  return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1, char* buf2,int width)
{
  int i = 0;
  for (i = 0; i < width; i++)
  {
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
  }
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2))
{
  //base 待排序数组的第一个元素
  //元素个数和元素个数的大小不可能是负数,所以是size_t类型
  //函数指针
  //要确定趟数
  size_t i = 0;
  for (i = 0; i < num - 1; i++)
  {
    //一趟冒泡排序的过程
    size_t j = 0;
    int flag = 1;//假设已经有序了
    //标记变量
    for (j = 0; j < num - 1 - i ; j++)
    {
      //两个相邻的元素比较
      //arr[j] arr[j+1]
      if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
      {
        //强制类型转换为char*
        //因为base为void类型,不能之间进行加减乘除,所以强制类型转换,但是又不能转换为int*,因为不一定就排序整型数组
        flag = 0;
        //交换
        Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
      }
    }
    if (flag == 1)
    {
      break;
    }
  }
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
void test3()
{
  int arr[] = { 3,1,5,2,4,9,8,6,7,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
  print_arr(arr, sz);
}
int main()
{
  test3();
  return 0;
}

1ac4a77e10b94f47afe95c401b215883.png

好啦,小雅兰玩转的qsort就到这里啦,这篇博客难度很大,确实花了小雅兰很多时间,未来还要继续加油呀!!!

8300a9e2baa64689ac83e9d4d174b64a.jpg

32621b18c04741afaefc97e74177475e.jpg

614cdc55e2df4c1c8b82a44a4dd04a4a.jpg


相关文章
|
7月前
|
编译器 C语言
库函数qsort的使用及利用冒泡排序模拟实现qsort
库函数qsort的使用及利用冒泡排序模拟实现qsort
|
算法 C语言
my_qsort,你值得拥有.
my_qsort,你值得拥有.
34 0
|
7月前
|
搜索推荐 C语言
冒泡排序模拟实现qsort()函数
冒泡排序模拟实现qsort()函数
45 0
|
7月前
浅学指针(4)函数指针数组和qsort的使用
浅学指针(4)函数指针数组和qsort的使用
|
存储 算法 测试技术
深入解析 qsort 函数(下),用冒泡排序模拟实现 qsort 函数
深入解析 qsort 函数(下),用冒泡排序模拟实现 qsort 函数
54 0
|
存储 算法 搜索推荐
21.【冒泡排序与选择排序与malloc()函数】
21.【冒泡排序与选择排序与malloc()函数】
86 0
|
C语言
妙用指针实现qsort
妙用指针实现qsort
80 0
|
算法 搜索推荐 JavaScript
冒泡实现qsort
冒泡算法 qsort函数
|
C语言
C语言-排序-快速排序-qsort<stdlib.h>
想到排序,大多数人第一个想到的都是冒泡排序,今天介绍一种函数,叫快速排序qsort函数,在讲这个函数之前,先将冒泡排序(数字)的代码给大家,如果想排序字符串,请大家使用strcmp函数即可