关于C语言qsort函数详解

目录
  • C语言qsort函数详解
    • 一.qsort函数是什么
    • 二.使用qsort排序-以升序为例
      • 1.整形数组排序
      • 2.字符数组排序
      • 3.字符指针数组排序
      • 4.结构体数组排序
      • 5.浮点型数组排序
    • 三.使用冒泡排序思想模拟实现qsort函数
      • 1.什么是冒泡排序
      • 2.冒泡排序代码
      • 3. 使用冒泡排序思想模拟实现qsort函数

C语言qsort函数详解

一.qsort函数是什么

我们可以使用  搜索库函数网址或者MSDN软件进行查找。

qsort()函数:快速排序的函数  -引用stdlib.h头文件

参数说明:

void qsort ( 

    void* base, //要排序的目标数组
    size_t num,     //待排序的元素个数
    size_t width,    //一个元素的大小,单位是字节
    int(*cmp)(const void* e1, const void* e2)

);

其中cmp是函数指针,cmp指向的是:排序时,用来比较两个元素的函数。需要自己编写。

返回值:

二.使用qsort排序-以升序为例

关于void*型指针:

void*:无具体类型的指针   能够接收任意类型的地址
 缺点:不能进行运算。不能+-整数,不能解引用

int a  = 0;
float f = 5.5f;
void* p1 = &a;
void* p2 = &f;
p1 = p1+1;    //err

1.整形数组排序

注意:

(1).比较函数的参数类型为void* ,我们要进行强制类型转换!且要解引用才能得到对应的值!

(2).若我们想排成降序,只需要写成e2-e1即可

void Print(int* arr, int sz)
{
 int i = 0;
 for (i = 0; i < sz; i++)
 {
  printf("%d ", *(arr + i));
 }
 printf("\n");
}
//比较整形
//注意类型时void* 所以要强制类型转化,还要解引用才是对应的值!!!
int cmp_int(const void* e1, const void* e2)
{
 return *(int*)e1 - *(int*)e2;
}
void test1()
{
 int arr[] = { 9,8,7,6,7,5,4,8 };
 int sz = sizeof(arr) / sizeof(arr[0]);
 qsort(arr, sz, sizeof(arr[0]), cmp_int);
 Print(arr, sz);
}

2.字符数组排序

注意使用sizeof()操作符strlen()函数的区别

//注意要要强制类型转换!! 要解引用!!!  本质上是比较Ascii值
int cmp_char(const void* e1, const void* e2)
{
    return *(char*)e1 - *(char*)e2;
}
void test4()
{
 char arr[] ="mango";
    //若使用sizeof计算长度:
 //int sz = sizeof(arr) / sizeof(arr[0]); //6
 //qsort(arr, sz-1, sizeof(arr[0]), cmp_float);
    //因为sizeof把\0也算进去了,所以计算出来的值比字符串本身长度多1

    int sz = strlen(arr); //5
    qsort(arr, sz, sizeof(arr[0]), cmp_char);
 printf("%s\n",arr);
}

3.字符指针数组排序

先看看下面这段程序有没有问题?

int cmp_chars(const void* e1, const void* e2)
{
 return strcmp((char*)e1, *(char*)e2);
}
void test2()
{
  char* arr1 = "abc";
  char* arr2 = "wcad";
  char* arr3 = "cab";
  char* p[3] = { arr1,arr2,arr3 };
 int sz = sizeof(p) / sizeof(p[0]);
 qsort(p, sz, sizeof(p[0]), cmp_chars);
 int i = 0;
 for (i = 0; i < sz; i++)
 {
  printf("%s\n", p[i]);
 }
}

打印出来发现:结果是错误的!

->调试后发现:e2存放的是p的地址(char**类型),e1存放的是p指向的下一个元素的地址(char**类型)

对于这种写法,传进去的是p的地址,strcmp()会将p地址对应的内容转化成字符串,也就是将p中arr1,arr2,arr3的地址转化成字符串

实际上应该传p地址空间中arr1,arr2的地址,这样strcmp()才能找到arr1和arr2对应的字符串,因此得先把e1,e2转化成char**,这样解引用以后才是一个char*的地址

原因:把p传给qsort,p是数组名->首元素地址,元素类型为char*>,所以p的类型为:char**类型。  所以e1 和e2也要强制类型转化为char**,解引用e1,e2才是对应字符串的地址!

正解:

int cmp_chars(const void* e1, const void* e2)
{
 return strcmp(*(char**)e1, *(char**)e2);
}
void test2()
{
  char* arr1 = "abc";
  char* arr2 = "wcad";
  char* arr3 = "cab";
  char* p[3] = { arr1,arr2,arr3 };
 int sz = sizeof(p) / sizeof(p[0]);
 qsort(p, sz, sizeof(p[0]), cmp_chars);
 int i = 0;
 for (i = 0; i < sz; i++)
 {
  printf("%s\n", p[i]);
 }

4.结构体数组排序

比较年龄->实际比较的是整形

比较名字->实际比较的是字符串->使用strcmp函数,不能使用 == 判断

struct Stu
{
 int age;
 char name[20];
};
//比较结构体中元素的年龄
int cmp_age(const void* e1, const void* e2)
{
 //本质是比较整形
 return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//比较名字
int cmp_name(const void* e1, const void* e2)
{
 //本质是字符串比较->使用strcmp函数
 return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test2()
{
 //创建结构体数组,用大括号初始化
 struct Stu s[3] = { {19,"Mango"},{18,"Lemon"},{20,"Hello"} };
 int sz = sizeof(s) / sizeof(s[0]);
 //以年龄排
 qsort(s, sz, sizeof(s[0]), cmp_age);
 printf("%s %d ",s[0].name,s[0].age);
 printf("%s %d ", s[1].name, s[1].age);
 printf("%s %d ", s[2].name, s[2].age);
 printf("\n");
 //以姓名排
 qsort(s, sz, sizeof(s[0]), cmp_name);
 printf("%s %d ", s[0].name, s[0].age);
 printf("%s %d ", s[1].name, s[1].age);
 printf("%s %d ", s[2].name, s[2].age);
 printf("\n");
}

5.浮点型数组排序

注意:比较函数中,返回类型是int,最后相减的值要强制类型转化为int ,但这也会造成错误,建议使用方法2.

写法1:可能会出错

// 原因: 0.2 -0.1 = 0.1 强制类型转化为int后 结果为0
//int cmp_float(const void* e1, const void* e2)
//{
// //返回类型是int  所以相减后的结果要强制类型转化
// return (int)(*(float*)e1 - *(float*)e2);
//}

写法2:对应上qsort的返回值

int cmp_float(const void* e1, const void* e2)
{
 if ((*(float*)e1 - *(float*)e2) > 0.00000)
  return 1;
 else if ((*(float*)e1 - *(float*)e2) == 0.000000)
  return 0;
 else
  return -1;
}
void test3()
{
 float arr[5] = { 5.01f,5.01f,0.02f,0.01f,5.001f };
 int sz = sizeof(arr) / sizeof(arr[0]);
 qsort(arr, sz, sizeof(arr[0]), cmp_float);
 int i = 0;
 for (i = 0; i < sz; i++)
 {
  printf("%f ", arr[i]);
 }
}

三.使用冒泡排序思想模拟实现qsort函数

1.什么是冒泡排序

主要思想:相邻的两个元素进行比较

对于冒泡排序: n个元素 共进行n-1趟冒泡排序。一趟可以使一个元素在特定位置上,每趟排序可以少比较一个元素

但是冒泡排序只能排序整形

2.冒泡排序代码

void BubbleSort(int* arr, int sz)
{
 int i = 0;
 int j = 0;
 //共进行sz-1趟
 for (i = 0; i < sz-1; i++)
 {
  int flag = 1;//每一趟进来都假设有序
        // 每一趟
  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;
    flag = 0;
   }
  }
        //若falg还是1,说明没有交换->已经有序了break退出
  if (flag == 1)
  {
   break;
  }
 }
}
int main()
{
 int arr[10] = { 2,3,6,7,9,0,0,3,2,10 };
 int sz = sizeof(arr) / sizeof(arr[0]);
 BubbleSort(arr, sz);
 return 0;
}

3. 使用冒泡排序思想模拟实现qsort函数

qsort库函数使用的是什么参数,我们设计的函数就使用什么参数!

(1)为何将base强制类型转化为char*型指针:

原因:char* 指针+1跳过一个字节,+width:跳过width个字节,指向下一个元素。转化为其他类型不合适

(2)交换函数:还要把宽度(每个元素所占字节数)传过去

因为交换的时候是传地址,所以要知道元素的宽度,一个字节一个字节的交换 ,这样也证明了使用char*指针的好处!

(3)char*)base + j * width, (char*)base + (j + 1) * width,

当j = 0时:比较的是第一个元素和第二个元素
   j = 1时,比较的是第二个元素和第三个元素
    ....  很妙的写法

//交换 --一个字节一个字节的交换,共交换width次
void Swap(char* buf1, char* buf2, size_t width)
{
 size_t i = 0;
 for (i = 0; i < width; i++)
 {
  char tmp = *buf1;
  *buf1 = *buf2;
  *buf2 = tmp;
  buf1++;
  buf2++;
 }
}
void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2))
{
 //冒泡排序
 //若要排序n个元素,只需要进行n-1趟
 //每一趟可以少比较一个元素,每一趟可以使一个元素在确定的位置上
 //num:要排序元素的个数 类型是size_t
    //num是无符号数 防止产生警告 所以i和j也定义为size_t
    // size_t == unsigned int
 size_t i = 0;
 size_t j = 0;

 //共进行num-1趟
 for (i = 0; i < num; i++)
 {
  //每一趟
  for (j = 0; j < num - 1 - i; j++)
  {
   //比较
   //传地址
   //相邻两个元素比较   width:宽度,每个元素所占字节
   //排成升序
   if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
   {
    //交换两数
    Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );
   }
  }
 }
}

当然 ,交换也可以使用库函数memcpy

dest:目标空间

 src:要拷贝到目标空间的字符 -因为不作修改,所以可以用const修饰

count:字节数

char tmp [30];    //防止结构体类型之类的类型    临时空间
memcpy(tmp, (char*)base + j * size, size);
memcpy( (char*)base + j * size,  (char*)base + (j + 1) * size, size);
memcpy( (char*)base + (j + 1) * size, tmp, size);

以上就是关于C语言qsort函数详解的详细内容,更多关于C语言qsort函数的资料请关注我们其它相关文章!希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中qsort函数的用法实例详解

    C语言中qsort函数的用法实例详解 快速排序是一种用的最多的排序算法,在C语言的标准库中也有快速排序的函数,下面说一下详细用法. qsort函数包含在<stdlib.h>中 qsort函数声明如下: void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *)); 参数说明: base,要排序的数组 nmemb,数组中元素的数目 size,每个数组元素占用的内存空间,可使用si

  • C语言进阶教程之字符串&内存函数

    目录 前言: 一.求字符串长度 strlen strlen函数的模拟实现 二.长度不受限制的字符串函数 strcpy strcpy函数的模拟实现 strcat strcat函数的模拟实现 strcmp strcmp函数的模拟实现 三.长度受限制的字符串函数 strncpy strncpy函数的模拟实现 strncat strncat函数的模拟实现 strncmp strncmp函数的模拟实现 四.字符串查找 strstr strstr函数的模拟实现 strtok strtok函数的模拟实现 五.

  • C语言快速排序函数用法(qsort)

    本文实例为大家分享了C语言快排函数用法,供大家参考,具体内容如下 #include <stdio.h> #include <stdlib.h> #include <string.h> struct student { int id; char name[12]; char sex; }; int compare(const void* a,const void* b)//基本数据类型排序 { return *(char*)a-*(char*)b;//从小到大 //取值/

  • C语言中qsort函数用法实例小结

    本文实例汇总了C语言中qsort函数的常见用法,非常具有实用价值.分享给大家供大家参考.具体分析如下: C语言中的qsort函数包含在<stdlib.h>的头文件里,本文中排序都是采用的从小到大排序. 一.对int类型数组排序 int num[100]; int cmp ( const void *a , const void *b ) { return *(int *)a - *(int *)b; } qsort(num,100,sizeof(num[0]),cmp); 二.对char类型数

  • C语言中qsort函数的介绍与用法实例

    目录 一.qsort函数是什么 二.使用qsort排序-以升序为例 1.整形数组排序 2.字符数组排序 3.字符指针数组排序 4.结构体数组排序 5.浮点型数组排序 三.使用冒泡排序思想模拟实现qsort函数 1.什么是冒泡排序: 2.冒泡排序代码 3. 使用冒泡排序思想模拟实现qsort函数 总结 一.qsort函数是什么 我们可以使用  搜索库函数网址或者MSDN软件进行查找. qsort()函数:快速排序的函数  -引用stdlib.h头文件 参数说明: void qsort ( void

  • 关于C语言qsort函数详解

    目录 C语言qsort函数详解 一.qsort函数是什么 二.使用qsort排序-以升序为例 1.整形数组排序 2.字符数组排序 3.字符指针数组排序 4.结构体数组排序 5.浮点型数组排序 三.使用冒泡排序思想模拟实现qsort函数 1.什么是冒泡排序 2.冒泡排序代码 3. 使用冒泡排序思想模拟实现qsort函数 C语言qsort函数详解 一.qsort函数是什么 我们可以使用  搜索库函数网址或者MSDN软件进行查找. qsort()函数:快速排序的函数  -引用stdlib.h头文件 参

  • C语言lseek()函数详解

     头文件: #include <sys/types.h> #include <unistd.h> 函数原型: off_t lseek(int fd, off_t offset, int whence);//打开一个文件的下一次读写的开始位置 参数: fd 表示要操作的文件描述符 offset是相对于whence(基准)的偏移量 whence 可以是SEEK_SET(文件指针开始),SEEK_CUR(文件指针当前位置) ,SEEK_END为文件指针尾 返回值: 文件读写指针距文件开头

  • Go语言init函数详解

    Go init函数详解 init()函数会在每个包完成初始化后自动执行,并且执行优先级比main函数高.init 函数通常被用来: 对变量进行初始化 检查/修复程序的状态 注册 运行一次计算 包的初始化 为了使用导入的包,首先必须将其初始化.初始化总是以单线程执行,并且按照包的依赖关系顺序执行.这通过Golang的运行时系统控制,如下图所示: 初始化导入的包(递归导入) 对包块中声明的变量进行计算和分配初始值 执行包中的init函数 initial.go package main import

  • C语言之qsort函数详解

    目录 一.qsort函数原型 二.qsort常见的几种比较函数 1.int类型的排序 2.double类型的排序 3.char类型的排序 4.字符串的排序: 1.按首字母排序 2.按字符串长度排序: 总结 一.qsort函数原型 qsort 功 能: 使用快速排序例程进行排序,这个函数是根据二分法写的,其时间复杂度为n*log(n) #include<stdlib.h> void qsort(void *base, int nelem, int width, int (*fcmp)(const

  • C语言fillpoly函数详解

    C语言中,fillpoly函数的功能是画一个多边形,今天我们就来学习学习. C语言fillpoly函数:填充一个多边形 函数名:fillpoly 功  能:画并填充一个多边形 头文件:#include <graphics.h> 原  型:fillpoly(int numpoints, int far *polypoints); 参数说明:numpoints 为多边形的边数:far *polypoints 为存储各顶点坐标的数组,每两个一组表示一个顶点的 X 和 Y 坐标. 实例代码: #inc

  • c语言 malloc函数详解

    谈到malloc函数相信学过c语言的人都很熟悉,但是malloc底层到底做了什么又有多少人知道. 1.关于malloc相关的几个函数 关于malloc我们进入Linux man一下就会得到如下结果: 也可以这样认为(window下)原型: extern void *malloc(unsigned int num_bytes); 头文件: #include<malloc.h>或者#include<alloc.h>两者的内容是完全一样的 如果分配成功:则返回指向被分配内存空间的指针 不

  • C语言memset函数详解

    目录 一.memset函数原型: 二.使用memset函数 三.给int类型赋值为1 四.扒开内存 五.memset给变量赋值 总结 在c语言中,使用变量前,需要先对变量的值进行初始化.数组在内存中占用一片连续的存储块.而c语言提供了memset函数(头文件string.h)对数组进行组团赋值.(memset函数也能对变量赋值,但只有无聊的人才会这么做.详见下文目录五) 一.memset函数原型: void memset ( void *s , char ch, unsigned n ) 函数功

  • C语言qsort函数使用方法详解

    目录 1.qsort函数 1.1qsort函数功能 1.2参数介绍 2.qsort函数功能测试 3.冒泡排序思想模拟实现qsort 1.qsort函数 void qsort (void* base, size_t num, size_t size, int (compar)(const void,const void*)); 1.1qsort函数功能 可以排序任何数据类型 对 所指向的数组元素进行排,使用函数确定顺序. 此函数使用的排序算法通过调用指定函数并指向元素的指针作为参数来比较元素. 该

  • C语言qsort()函数的使用方法详解

    目录 前言 1.参数含义 1.首元素地址base 2.元素个数num 3.元素大小size 4.自定义比较函数compar 2.使用方式 1.头文件 2.compar的实现 3.整体代码 总结 前言 qsort()函数(quick sort)是八大排序算法中的快速排序,能够排序任意数据类型的数组其中包括整形,浮点型,字符串甚至还有自定义的结构体类型. 1.参数含义 void qsort (void* base, size_t num, size_t size,int (*compar)(cons

  • C语言文件操作中 fgets与fputs 函数详解

    C语言文件操作中 fgets.fputs 函数详解 先给出api fgets 语法: #include <stdio.h> char *fgets( char *str, int num, FILE *stream ); 函数fgets()从给出的文件流中读取[num - 1]个字符并且把它们转储到str(字符串)中. fgets()在到达行末时停止,在这种情况下,str(字符串)将会被一个新行符结束. 如果fgets()达到[num - 1]个字符或者遇到EOF, str(字符串)将会以nu

随机推荐