【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

相关文章

Pandas利用主表更新子表指定列小技巧

《Pandas利用主表更新子表指定列小技巧》本文主要介绍了Pandas利用主表更新子表指定列小技巧,通过创建主表和子表的DataFrame对象,并使用映射字典进行数据关联和更新,实现了从主表到子表的同... 目录一、前言二、基本案例1. 创建主表数据2. 创建映射字典3. 创建子表数据4. 更新子表的 zb

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

C语言中位操作的实际应用举例

《C语言中位操作的实际应用举例》:本文主要介绍C语言中位操作的实际应用,总结了位操作的使用场景,并指出了需要注意的问题,如可读性、平台依赖性和溢出风险,文中通过代码介绍的非常详细,需要的朋友可以参... 目录1. 嵌入式系统与硬件寄存器操作2. 网络协议解析3. 图像处理与颜色编码4. 高效处理布尔标志集合

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

C 语言中enum枚举的定义和使用小结

《C语言中enum枚举的定义和使用小结》在C语言里,enum(枚举)是一种用户自定义的数据类型,它能够让你创建一组具名的整数常量,下面我会从定义、使用、特性等方面详细介绍enum,感兴趣的朋友一起看... 目录1、引言2、基本定义3、定义枚举变量4、自定义枚举常量的值5、枚举与switch语句结合使用6、枚

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java