【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)

2024-05-01 13:20

本文主要是介绍【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

请添加图片描述
请添加图片描述

Alt

🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅
请添加图片描述

文章目录

  • 一、回调函数
  • 二、快速排序(Qsort)
    • 2.1 Qsort参数部分介绍
    • 2.2 不同类型的比较方法
    • 2.3 简单使用Qsort(对任意数据类型进行排序)
  • 三、冒泡排序思想模拟实现快速排序(不是真正的快速排序)
    • 3.1 函数内部:
    • 3.2 底层逻辑解析
      • 3.2.1 判断语句:
      • 3.2.2 比较函数:
      • 3.2.3 Swap函数参数:
      • 3.2.4 Swap内部逻辑:


一、回调函数

回调函数通过一个函数指针调用的函数。把一个函数的地址作为一个参数传递给另外一个函数,当这个地址被用来调用其指向的函数时,被调用函数称为回调函数(跟函数嵌套差不多

//使⽤回到函数改造后
#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}int d(int a, int b)
{return a / b;
}void calc(int(*pf)(int, int))
{int ret = 0;int x, y;printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}int main()
{int input = 1;do{scanf("%d", &input);switch (input){case 1:calc(add);break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(d);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

二、快速排序(Qsort)

快速排序属于九大排序之一,并且该函数在头文件stdlib.h 声明
请添加图片描述

2.1 Qsort参数部分介绍

void qsoer(void *base, size_t num, size_t size, int (*compare)(const void*,const void*))
  • void * base:待排序数据的起始位置,第一个元素
  • size_t num:待排序数据的元素个数
  • size_t size:待排序数据的每个元素的大小,单位是字节
  • int (*compare)(const void *,const void *):函数指针-指针指向的函数是来比较待排序数据中的两个元素大小关系

注意】:void 是无具体类型的指针(通用指针类型),对此可以接收任意数据类型的地址

2.2 不同类型的比较方法

提前说明】:关于比较函数的参数部分,void *是无具体类型的指针(通用指针类型),对此可以接收任意数据类型的地址。

整形类型:

int int_compare(const void* e1, const void* e2)
{return *((int*)e1) - *((int*)e2);
}

字符类型(比较单字符的大小,字符串函数头文件string.h):

int char_compare(const void* e1, const void* e2)
{return strcmp((char*)e1, (char*)e2);
} 

字符串长度

int charnums_compare(const void* e1, const void* e2)
{return strlen((char*) e1) - strlen((char*) e1);
}

结构体整形成员

int  int_age_compare(const void* e1, const void* e2)
{return ((struct su*)e1)->age - ((struct su*)e2)->age;
}

结构体字符串成员

int char_name_compare(const void* e1, const void* e2)
{return strcmp(((struct su*)e1)->name, ((struct su*)e1)->name);
}

说明】:不同类型数据的比较不能单单只通过大于小于号去判断,需要掌握不同类型的比较方法,以便于更好的使用qsort函数,但是在C++中,一般使用sort,而不是qsort函数,因为使用起来很复杂,而且需要自己实现个比较函数。

2.3 简单使用Qsort(对任意数据类型进行排序)

struct su
{int age;char name[100];
};
int main()
{int nums[] = { 2,6,7,9,10,1,8,5,3 };int sz = sizeof(nums) / sizeof(nums[0]);qsort(nums, sz, sizeof(nums[0]), compare);//函数名变身就是一个函数指针变量//结构体数组struct su s[] = { {18,"zhangsana"},{14,"xiaoming"},{9,"lierdan"} };int sz2 = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), age_compare);return 0;}

三、冒泡排序思想模拟实现快速排序(不是真正的快速排序)

前文:冒泡排序是一种简单的排序,但是只能排序整形数据,无法适应不同类型的场景。对此,我们将通过冒泡排序的思想模拟实现一个对任意类型能排序的快速排序

注意】:快速排序的底层不是这样子实现的,对此这里不是真正的快速排序

int main()
{int nums[] = { 2,6,7,9,10,1,8,5,3 };int sz = sizeof(nums) / sizeof(nums[0]);int with = sizeof(nums[0]);my_qsort(nums, sz, with, int_compare);return
}

3.1 函数内部:

void my_qsort(int* p, int sz, int width, int (*compare)(const void* e1, const void* e2))
{for (int i = 0; i < sz - 1; i++){for (int j = 0; j < sz - i - 1; j++){		if(compare((char*)base+j*width,(char *)base+(j+1)*width)>0)//compare 根据类型去定义{ Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}

【说明】:函数实现框架跟冒泡排序相似,主要的不同在于判断和交换语句底层逻辑的不同


3.2 底层逻辑解析

3.2.1 判断语句:

if(compare((char*)base+j*width,(char *)base+(j+1)*width))

说明】:

强制类型转化为char*类型(char *类型对于±整形,偏移量为一个字节)。width是某个类型的大小,那么这两个参数之间相差width大小,正好跳过某个类型元素。(适用于任意的数据进行比较)

3.2.2 比较函数:

int int_compare(const void* e1, const void* e2)//对比分类型
{return *(int*)e1 - *(int*)e2;
}

函数名】:int_compare表明了这里适合对整形数据对比,对于不同数据类型有不同的比较方法,在上面使用库函数qsort中有所涉及

3.2.3 Swap函数参数:

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

说明】:base是待排序数据的起始位置(首元素的地址),强制类型转化为char*类型,使得对于±整型,偏移量为一个字节。width是某个类型的大小,那么这两个参数之间相差width大小,正好跳过某个类型元素(j * width(j + 1) * width )。(适用于任意的数据进行比较)

3.2.4 Swap内部逻辑:

void Swap(char* e1, char* e2,int width)
{for (int i = 0; i<width;i++){char tmp = *e1;*e1 = *e2;*e2 = tmp;e1++;e2++;}
}

说明】:强制类型转化为char *的目的是对于两个参数部分,逐一字节交换e1/2++不断向后移动到新的位置,再进行交换。Swap只交换一次,交换的字节数到达某类型的大小,则完成交换。(适用于任意的数据进行交换)


请添加图片描述

以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二C语言笔记,希望对你在学习C语言中有所帮助!

这篇关于【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/951797

相关文章

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

电脑win32spl.dll文件丢失咋办? win32spl.dll丢失无法连接打印机修复技巧

《电脑win32spl.dll文件丢失咋办?win32spl.dll丢失无法连接打印机修复技巧》电脑突然提示win32spl.dll文件丢失,打印机死活连不上,今天就来给大家详细讲解一下这个问题的解... 不知道大家在使用电脑的时候是否遇到过关于win32spl.dll文件丢失的问题,win32spl.dl

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

使用C语言实现交换整数的奇数位和偶数位

《使用C语言实现交换整数的奇数位和偶数位》在C语言中,要交换一个整数的二进制位中的奇数位和偶数位,重点需要理解位操作,当我们谈论二进制位的奇数位和偶数位时,我们是指从右到左数的位置,本文给大家介绍了使... 目录一、问题描述二、解决思路三、函数实现四、宏实现五、总结一、问题描述使用C语言代码实现:将一个整