C语言qsort()函数针对:整型、单个字符、字符串、结构体,超详细讲解(多维度分析举例,小白一看就懂!!!!!)

news2024/11/25 10:45:23

目录

一、前言

二、qsort()函数

 🍑qsort()函数简介

🍉qsort()函数中整型、double型、字符型的应用

💦整型

💦 double型

💦字符排序 

 🍎qsort()函数在字符串中的应用

💦在字符串中按首字母排序

💦字符串长度排序

💦字符串按字典顺序排序 

🍓结构体排序的应用

💦结构体多级排序

 三、共勉


一、前言

    在我了解到qsort()函数之前呢,对于我这个编程小菜狗来说,平时练习排序的时候就只会用到冒泡排序(代码复杂,且时间复杂度高),并且大部分只会应用到整型数据的排序,一旦遇到字符、字符串、结构体、或者要求时间复杂度的题题目时,基本可以说是两眼一抹黑,完全滴不会。于是,为了解决这一排序问题,我专门花了一早上的时间去研究全能的排序函数qsort()函数,在这里做出总结,希望对大家有用O!!!!

二、qsort()函数

 🍑qsort()函数简介

    排序方法有很多种:选择排序,冒泡排序,归并排序,快速排序等。 看名字都知道快速排序是目前公认的一种比较好的排序算法。因为它速度很快,所以系统也在库里实现这个算法,便于我们的使用。 这就是qsort函数(全称quicksort)。它是ANSIC标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为n*log(n)。

知识点1:

qsort()函数的头文件:#include <stdlib.h>

qsort()函数的声明:

 函数声明的解释:

#include <stdlib.h>
#include <stdio.h>
void qsort (void* base, size_t num, size_t size,int (*compar)(const void*, const void*));

 各个参数的理解:

void *base:void  指向任意类型的数据   *base 为待排序数组的起始位置的数据

size_t num:数组元素个数

size_t size :待排序元素数据的大小 (举例:int 型是4  ,char型是 1)

int (*compar)(const void*, const void*)  比较两个元素大小的函数指针----判断升序或降序

(此函数功能需要我们自己编写实现)

 加const表示无法改变指针指向的值。

 return * ( int * )a - * ( int * ) b ,返回一个整型数,表示两个元素对比的结果。如果a大于b,则返回正数。a小于b,则返回负数。如果a等于b,则返回零。

(int *)表示将地址强制类型转换成整形地址类型,可根据排序对象选择指针类型的转换。

如果大家还想了解更加详细的qsort()函数的声明可以进入这个网站了解:

qsort - C++ Reference (cplusplus.com)

🍉qsort()函数中整型、double型、字符型的应用

💦整型

知识点1:

首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_int (const void * a,const void *b)   //整型
 {
    int* a = (int*)_a;    //强制类型转换
    int* b = (int*)_b;
    return *a - *b;       // 升序
    return *b - *a;       // 降序
}

上面写的这种方法便于大家的理解,其实可以继续化简,使代码更加简洁

int cmp_int (const void * a,const void *b)
{
   return * (int * )a-* (int *)b;    //升序
   return * (int * )b-* (int *)a;    //降序
}

知识点2:

针对整型数据的排序举例,看代码:

#include <stdlib.h>
#include <stdio.h>
int cmp_int(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;    //升序
}
int main() 
{
	int arr[] = { 1, 3, 6, 2, 4, 8, 7, 10 };
	printf("排序前:");
	int sz = sizeof(arr) / sizeof(arr[0]);  //求出数组的长度
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		printf("%d  ", arr[i]);
	}
	qsort(arr, sz, sizeof(arr[0]), cmp_int);  // 进行排序
	printf("\n排序后:");
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		printf("%d  ", arr[i]);
	}
	return 0;
}

💦 double型

知识点1:

首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_double (const void * a, const void * b)
{
  return *(double *)a > *(double *)b ? 1 : -1;  //升序
  return *(double *)a < *(double *)b ? 1 : -1;  //降序
}

注意:

 这里两个浮点数相减但要返回一个整型数,如果按上面做法直接减会丢失小数点部分。所以需另加处理,直接判断大小,如果a大于b,则返回1,否则返回-1。

知识点2:
 针对double型数据的排序举例,看代码:

#include <stdlib.h>
#include <stdio.h>
int cmp_double(const void* a, const void* b)
{
	return *(double*)a > *(double*)b ? 1 : -1;  //升序
}
int main() 
{
	double arr[] = { 1.0, 3.0, 6.0, 2.0, 4.0, 8.0, 7.0, 10.0 };
	printf("排序前:");
	int sz = sizeof(arr) / sizeof(arr[0]);  //求出数组的长度
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		printf("%.2lf  ", arr[i]);
	}
	qsort(arr, sz, sizeof(arr[0]), cmp_double);  //进行排序
	printf("\n排序后:");
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		printf("%.2lf  ", arr[i]);
	}
	return 0;
}

 

💦字符排序 

知识点1:
首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_char(const void *a,const void *b)
{
   return *(char *)a - *(char *)b;  //升序
   return *(char *)a - *(char *)b;  //降序
}

知识点2:

针对double型数据的排序举例,看代码:

#include <stdlib.h>
#include <stdio.h>
int cmp_char(const void* a, const void* b)
{
	return *(char*)a - *(char*)b;    //升序
}
int main() 
{
	char arr[] = { 'b', 'd', 'a', 'c' };
	printf("排序前:");
	int sz = sizeof(arr) / sizeof(arr[0]);  //求出数组的长度
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		printf("%c  ", arr[i]);
	}
	qsort(arr, sz, sizeof(arr[0]), cmp_char);  //进行排序
	printf("\n排序后:");
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
	{
		//printf("");
		printf("%c  ", arr[i]);
	}
	return 0;
}

 

 🍎qsort()函数在字符串中的应用

💦在字符串中按首字母排序

知识点1:
首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_char(const void *a, const void *b)  
{  
  return * (char *)a - *(char * )b;   //升序
}  

针对字符串按首字母的排序举例,看代码:

#include<stdio.h>
#include<stdlib.h>
#define L 10
#define K 10
int cmp_char(const void* a, const void* b)
{
	return *(char*)a - *(char*)b;    //升序
}
int main()
{
	char a[L][K] = {
		"rbsc",
		"jcse",
		"efgd",
		"arbs",
		"bbs",
		"cbfe",
		"dgafg" ,
		"ewqrta",
		"ofgd",
		"mbcv",
	};
	qsort(a, L, sizeof(char) * K, cmp_char);   // 进行排序
	for (int i = 0; i < L; i++)
	{
		printf("%s\n", a[i]);
	}
	return 0;
}

注意:此时先申请一个二维数组,将二维数组的每一行看成一个一维数组,就可以得出,有L个一维数组,每个数组有K个元素。

💦字符串长度排序

知识点1:
首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_char(const void *a, const void *b)
{
	return strlen((char *)a) > strlen((char *)b) ? 1 : -1;  //升序
 }  

注:这里不要用 return strlen((char * )a) - strlen((char * )b) ;

原因:1. strlen返回类型为size_t,size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int。无符号整型最好不要做四则运算。

          2. 这里虽然函数返回int型,会把无符号数转换为整型,但返回结果只在字符串的长度未超过int的范围时正确。这种大范围转小范围要考虑精度损失的问题。

         3.这里大家可以看看我之前写的字符串函数:

(358条消息) C语言:常见字符串函数详解初阶(小白一看就懂,让你有一种相见恨晚的感觉哦!!!)_sunny-ll的博客-CSDN博客

针对字符串长度排序举例,看代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define L 10
#define K 10
int cmp_char(const void *a, const void *b)
{
	return strlen((char *)a) > strlen((char *)b) ? 1 : -1;  //升序
 } 
int main ()
{
	char a[L][K] = {
		"rbsc",
		"jcsse",
		"efgdsd",
		"arbs",
		"bbs",
		"cbfefaa",
		"dgafg" ,
		"ewqrta",
		"ofgd",
		"mbcv312",
	};
	qsort(a, L, sizeof(char) * K, cmp_char);
	for (int i = 0; i < L; i++)
	{
		printf("%s\n", a[i]);
	}
 } 

💦字符串按字典顺序排序 

知识点1:

首先写出针对整型的 比较函数: int (*compar)(const void*, const void*)

int cmp_char(const void *a, const void *b)
{
	return strcmp((char * )a, (char *)b);  //升序
} 

针对字符串字典顺序排序举例,看代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define L 10
#define K 10
int cmp_char(const void *a, const void *b)
{
	return strcmp((char * )a, (char *)b);   //升序
 } 
int main ()
{
	char a[L][K] = {
		"rbsc",
		"jcsse",
		"afgdsd",
		"arbs",
		"abs",
		"cbfefaa",
		"cgafg" ,
		"ewqrta",
		"ofgd",
		"mbcv312",
	};
	qsort(a, L, sizeof(char) * K, cmp_char);
	for (int i = 0; i < L; i++)
	{
		printf("%s\n", a[i]);
	}
 } 

🍓结构体排序的应用

💦结构体多级排序

结构体体的三级排序测试:
第一级是对学生成绩整体从小到大排序;
第二级是对相同成绩的学生,按照姓名进行排序;
第三级是对相同成绩、姓名的学生,按照学号进行排序;

代码举例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h> 
typedef struct student  //结构体类型
{
	int id;        //成绩
	char name[10]; //姓名
	int grade;     //学号
}student;          // 结构体变量

int cmp1(const void* a, const void* b)//一级排序 :对学生成绩整体从小到大排序
{
	student* s1 = (student*)a;          //指针强制转换为 结构体指针
	student* s2 = (student*)b;
	return s1->id - s2->id;
}

int cmp2(const void* a, const void* b)//二级排序:对相同成绩的学生,按照姓名进行排序
{
	student* s1 = (student*)a;
	student* s2 = (student*)b;
	if (strcmp(s1->name, s2->name) != 0)
		return strcmp(s1->name, s2->name);
	else
		return s1->id - s2->id;
}

int cmp3(const void* a, const void* b)//三级排序 :对相同成绩、姓名的学生,按照学号进行排序
{
	student* s1 = (student*)a;
	student* s2 = (student*)b;
	if (s1->grade != s2->grade)
		return s1->grade - s2->grade;
	else
	{
		if (strcmp(s1->name, s2->name) != 0)
			return strcmp(s1->name, s2->name);
		else
			return s1->id - s1->id;
	}
}

int main()
{
	int i, N, C;
	scanf("%d %d", &N, &C);

	student* stu;
	stu = (student*)malloc(N * sizeof(student));

	for (i = 0; i < N; i++)
		scanf("%d %s %d", &stu[i].id, stu[i].name, &stu[i].grade);
	switch (C)
	{
	case 1:	qsort(stu, N, sizeof(student), cmp1); break;//一级排序
	case 2:	qsort(stu, N, sizeof(student), cmp2); break;//二级排序
	case 3:	qsort(stu, N, sizeof(student), cmp3); break;//三级排序
	}
	printf("排序结果:\n");
	for (i = 0; i < N; i++)
		printf("%03d %s %d\n", stu[i].id, stu[i].name, stu[i].grade);
	return 0;
}

 三、共勉

以下就是我对C语言qsort()函数的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对结构体理解,请持续关注我哦!!!!! 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android NDK开发基础

文章目录cmake语法基础cmake添加日志&#xff1a;cmake增加宏字符串比较cmake在build.gradle中传递编译参数到cmake通过javah生成native对应的c头文件jni和java之间字符串的相互操作JavaVM和JNIEnv字符串的编码native方法静态注册和动态注册静态注册动态注册extern cC中STATIC和…

SpringCloud Alibaba-Sentinel保姆级教程

文章目录1、Sentinel前奏1.1、服务雪崩效应1.2、常见容错方案1、隔离2、超时3、限流4、熔断5、降级1.3、常见容错组件1、Hystrix2、Resilience4J3、Sentinel2、Sentinel入门2.1、什么是Sentinel2.2、实战编码1、安装Sentinel服务端2、微服务引入Sentinel2.3、Sentinel流控模式1…

YOLOv5蒸馏 | 知识蒸馏理论篇 | 1/2

之前在《一文搞懂【知识蒸馏】【Knowledge Distillation】算法原理》这篇文章中介绍过一些知识蒸馏的原理,这篇博文将会着重介绍目标检测领域的知识蒸馏原理。 文章目录 1.《Object detection at 200 Frames Per Second》1.1 蒸馏难点1.2 蒸馏损失1.3 实验结果2. 《Learning E…

计算机毕业设计ssm+vue基本微信小程序的体检预约小程序

项目介绍 我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;体检预约系统小程序被用户普遍使用&#xff0c;为方便用户…

【前端】CSS(1) —— CSS的基本语法和一些简单的选择器

JavaEE传送门JavaEE 网络原理——网络层与数据链路层 【前端】HTML入门 —— HTML的常见标签 目录CSS基本语法注释引入方式内部样式内联样式外部样式代码风格样式格式样式大小写空格规范CSS 选择器标签选择器类选择器id 选择器通配符选择器复合选择器后代选择器子选择器并集选…

文件包含漏洞和hash破解

介绍 Windows是当今世界最主要的操作系统&#xff0c;因为它易于使用的GUI可访问性。大约85%的市场份额已成为攻击的关键操作系统。此外&#xff0c;大多数组织使用Active Directory来设置其Windows域网络。微软聘请NTLM&#xff08;New Technology LAN Manager&#xff09;和…

Pico Neo3 4VR游戏下载地址及十大好玩游戏推荐

大家好&#xff0c;杰克今天为大家分享的是VR一体机游戏。 说到VR一体机&#xff0c;我们首先想到的一定是国产之光pico啦&#xff0c;picovr被认为是国内最被看好的VR一体机&#xff0c;有望在国内取代红极一时的OculusQuest&#xff0c;填补这块市场的空白。OculusQuest将6D…

#Primavera Unifier:关于零代码/低代码平台特点【2/3】

在之前对Unifier的介绍中&#xff0c;我提到了Unifier应用的一个非常关键的特征&#xff0c;及零代码快速配置使用&#xff0c;而为了更好的介绍Oracle Primavera Unifier 的零代码特点&#xff0c;以下我将通过3篇内容来逐一介绍零代码/低代码平台的特点。 前面介绍到了零代码…

Opencv项目实战:14 手势控制音量

目录 0、项目介绍 1、项目展示 2、项目搭建 3、项目的代码与讲解 4、项目资源 5、项目总结 0、项目介绍 本篇与上一篇有很多联系&#xff0c;大家可以看看这篇Opencv项目实战&#xff1a;13 手部追踪&#xff0c;我们将根据上一节的内容&#xff0c;进行一个拓展。本篇你…

AtCoder Beginner Contest 275 【E】【F】

E - Sugoroku 4 【概率dp】 题意&#xff1a; 对于每个样例&#xff0c;读入n&#xff0c;m&#xff0c;k。 一维数轴&#xff0c;你现在在0这个点上&#xff0c;目标是到达n这个点&#xff0c;你有k次掷骰子的机会&#xff0c;每次可能等概率的掷出1~m的任意一个数字&#xff…

面了一个4年经验的测试工程师,自动化都不会也要15k,我真是醉了...

在深圳这家金融公司也待了几年&#xff0c;被别人面试过也面试过别人&#xff0c;大大小小的事情也见识不少&#xff0c;今天又是团面的一天&#xff0c; 一百多个人都聚集在一起&#xff0c;因为公司最近在谈项目出来面试就2个人&#xff0c;无奈又被叫到面试房间。 整个过程…

.NET Core HttpReports 监控

HttpReports 基于.NET Core 开发的APM监控系统&#xff0c;使用MIT开源协议&#xff0c;主要功能包括&#xff0c;统计, 分析, 可视化&#xff0c; 监控&#xff0c;追踪等&#xff0c;适合在中小项目中使用。 语雀&#xff1a;https://www.yuque.com/httpreports/docs/uyaiil …

SQL注入之绕过is_numeric过滤

目录预备知识PHP常用的过滤类函数is_numeric()函数介绍实验目的实验环境实验步骤一通过源代码审计&#xff0c;发现临时文件实验步骤二通过分析源代码的执行逻辑&#xff0c;了解程序的功能&#xff0c;发现程序中的安全漏洞实验步骤三绕过过滤函数实现SQL注入预备知识 PHP常用…

Linux进程信号

文章目录什么是信号signal函数的功能&#xff08;捕捉信号后自己处理&#xff09;Core Dump&#xff08;核心转储&#xff09;kill&#xff0c;raise&#xff0c;alarm系统调用再度理解OS给进程发送信号信号集操作函数自定义捕捉详解什么是信号 生活中的信号&#xff1a;闹钟&…

0083 环形链表

package LinkedList_; /* * 单向环形链表应用场景——约瑟夫问题 * 设编号为1&#xff0c;2....n的n个人围成一圈&#xff0c;约定编号为k&#xff08;1<k<n&#xff09;的人从1开始报数&#xff0c;数到m的人出列&#xff0c; * 它的下一位又从…

黑胶歌曲没权限,还好我会Python,一分钟一个歌单,硬盘有点不够用了~

今日份Python白嫖人生苦短&#xff0c;我用Python一、你需要准备1、环境2、模块二、效果展示三、代码展示四、写在最后人生苦短&#xff0c;我用Python 人之初&#xff0c;喜白嫖。大家都喜欢白嫖&#xff0c;我也喜欢&#xff0c;那么今天就来试试怎么白嫖抑云~ 我不是&#…

React面向组件编程(定义组件,组件三大核心属性,组件事件处理、组件收集表单数据、高阶函数和函数的柯里化)

目录 一、React中定义组件 1、函数式组件 2、类式组件 二、组件三大核心属性 1、组件三大核心属性1: State(状态) 2、组件三大核心属性2: props 3、组件三大核心属性3: ref 三、组件事件处理 1、事件处理 四、组件收集表单数据 1、受控组件 2、非受控组件 五、高阶函…

【数据结构】算法的时间复杂度和空间复杂度

&#x1f680; 作者简介&#xff1a;一名在后端领域学习&#xff0c;并渴望能够学有所成的追梦人。 &#x1f40c; 个人主页&#xff1a;蜗牛牛啊 &#x1f525; 系列专栏&#xff1a;&#x1f6f9;初出茅庐C语言、&#x1f6f4;数据结构 ☀️ 学习格言&#xff1a;眼泪终究流不…

象棋中的马跳步问题

象棋中的马跳步问题 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;象棋中的马跳步问题 CSDN&#xff1a;象棋中的马跳步问题 题目描述 中国象棋中&#xff0c;整个棋盘就是横坐标上 9 条线、纵坐标上 10 条线的一个区域&#xff0c;给你三个 参数 x&…

计算机毕业设计springboot+vue基本微信小程序的汽车租赁公司小程序

项目介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时…