【C语言】剖析qsort函数的实现原理

主页:17_Kevin-CSDN博客

专栏:《C语言》

本文将从回调函数,qsort函数的应用,qsort函数的实现原理三个方面进行讲解,请自行跳转至相对位置进行阅读~ 

目录

回调函数

qsort函数的应用

qsort函数实现原理

回调函数

什么是回调函数?

回调函数实际上是一个指针,指向的是一个函数。它作为一个参数传递给另一个函数,并且在特定的条件下被执行。

回调函数的作用

回调函数的主要作用是使代码更加灵活和模块化。通过使用回调函数,我们可以将特定的行为或逻辑与原始函数分离开来,这样可以让我们更容易地进行代码重用和维护。

回调函数的实现

定义一个函数,然后将其作为参数传递给其他函数,在特定条件下执行

回调函数的示例

让我们以 C 语言为例,来看一个简单的回调函数示例:

#include <stdio.h>void performOperation(int a, int b, int (*callback)(int, int))
{int result = callback(a, b);printf("The result is: %d\n", result);
}int add(int a, int b)
{return a + b;
}int main()
{int x = 10, y = 20;performOperation(x, y, add);  // 传递 add 函数作为回调函数return 0;
}

在这个示例中,performOperation 函数接受两个整数和一个函数指针作为参数,然后在内部调用传递进来的函数指针,实现了加法运算。在主函数中,我们将 add 函数作为回调函数传递给 performOperation 函数。这就是一个简单的回调函数的例子。

qsort函数的应用

函数定义

在官方文档中qsort的函数定义如下:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*));

函数参数的剖析

base:

参数base是一个void* 类型的,qsor使用来排序的函数,该参数就是传入的要进行排序的数组。作为一个void*类型的指针,我们传入数组的地址,即可完成对要排序数组的传入。

num:

该参数位置要传入的是要进行排序的数组的元素个数,一般使用sizeof(数组名)/ sizeof(数组中的任意元素)进行计算得到个数。

size:

参数size传入的参数是数组中单个元素的大小,该参数可以确保在函数内排序的时候每次跳跃的字节大小是一个元素的字节的大小。

compar:
该参数是一个函数指针,指向比较两个元素的函数。 qsort内部会反复调用此函数来比较两个元素,以此来决定排序方向。

请注意!在传入该参数的时候请严格按照该参数的规范结构来书写。

int (*compar)(const void*,const void*)

为什么要用void*?

这是因为 qsort 函数可以对任意类型的数组进行排序,而不同类型的数据可能需要不同的比较方法。使用 void* 类型作为参数可以让比较函数更加通用,因为 void* 是一种无类型指针,可以指向任何类型的数据。在比较函数内部,我们可以将 void* 类型的指针转换为实际的数据类型再进行比较(强制类型转化)。

通过使用 void* 类型,可以在不知道具体数据类型的情况下编写通用的比较函数,使 qsort 函数更加灵活和通用。在比较函数中,我们需要负责将 void* 类型的指针转换为实际的数据类型,并进行比较操作。

使用 void* 类型的参数可以使比较函数更加通用,适用于不同类型的数据,从而增强了函数的灵活性和通用性。

经典代码示例

#include <stdio.h>
#include <stdlib.h>// 比较函数,用于升序排序
int compare(const void *a, const void *b) {return (*(int*)a - *(int*)b);
}int main() {int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};int n = sizeof(arr) / sizeof(arr[0]);// 使用 qsort 对数组进行排序qsort(arr, n, sizeof(int), compare);printf("Sorted array: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}

在这个示例中,首先定义了一个整型数组 arr,然后通过 qsort 函数对数组进行排序。在 main 函数中,我们计算数组的大小 n,然后调用 qsort 函数,传入数组、数组大小、每个元素的大小以及比较函数 compare。比较函数 compare 中,我们将 void* 类型的指针转换为 int* 类型,并进行升序排序。最终得到的就是升序排序的数组了。

qsort函数实现原理

详细定义

qsort 函数是一个用于快速排序(Quick Sort)的标准库函数。它接受一个数组和一个比较函数作为参数,并对数组进行排序。快速排序是一种分治的排序算法,通过选择一个基准元素,将数组分为两部分,一部分比基准元素小,一部分比基准元素大,然后对这两部分递归地进行排序,最终得到一个有序的数组。

实现原理

  1. 选择基准元素qsort 函数首先选择数组中的一个元素作为基准元素。通常情况下,可以选择数组的第一个元素作为基准元素。

  2. 分区(Partition)qsort 函数使用选定的基准元素将数组分为两部分,一部分小于等于基准元素,另一部分大于基准元素。这个过程称为分区。

  3. 递归排序qsort 函数递归地对小于等于基准元素和大于基准元素的两部分进行排序。它分别对这两部分调用 qsort 函数,并将相应的比较函数传递给子函数。

  4. 合并结果:最后,qsort 函数将排序后的两部分合并起来,形成一个有序的数组。

模拟实现sort

以下代码使用C语言模拟实现qsort函数的代码:

#include <stdio.h>void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}int partition(int arr[], int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j <= high - 1; j++) {if (arr[j] < pivot) {i++;swap(&arr[i], &arr[j]);}}swap(&arr[i + 1], &arr[high]);return i + 1;
}void quickSort(int arr[], int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}void myQsort(int arr[], int n) {quickSort(arr, 0, n - 1);
}int main() {int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};int n = sizeof(arr) / sizeof(arr[0]);myQsort(arr, n);printf("Sorted array: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}

这是一个以快速排序为基础的qsort函数实现,通过选择一个基准元素,并将数组分成两部分,使得左边的元素都小于或等于基准元素,而右边的元素都大于基准元素,然后对左右两部分递归地进行排序,最终得到一个有序的数组。

以下是各个函数的分解解析:

  1. swap 函数:这个函数用于交换两个整数的值。它接受两个整数指针作为参数,并使用 temp 变量来暂存其中一个整数的值,然后将两个整数的值进行交换。
  2. partition 函数:这个函数用于将一个数组的某个子数组分成两部分,使得左边的元素都小于或等于基准元素,而右边的元素都大于基准元素。它接受一个整数数组、子数组的起始索引和结束索引作为参数。首先,它选择最后一个元素作为基准元素,并将 i 初始化为 low - 1。然后,它使用一个循环从 low 到 high - 1 遍历数组,如果当前元素小于基准元素,就将 i 向右移动一个位置,并将当前元素和 arr[i] 进行交换。最后,它将基准元素和 arr[i + 1] 进行交换,使得基准元素位于正确的位置上。
  3. quickSort 函数:这个函数用于对一个数组进行快速排序。它接受一个整数数组和起始索引和结束索引作为参数。如果起始索引小于结束索引,它就调用 partition 函数将数组分成两部分,并对左右两部分递归地进行排序。
  4. myQsort 函数:这个函数是一个封装的快速排序函数,它接受一个整数数组和数组的大小作为参数,并调用 quickSort 函数对数组进行排序。
  5. main 函数:这个函数是程序的入口函数。它首先定义了一个整数数组 arr,并计算数组的大小。然后,它调用 myQsort 函数对数组进行排序,并打印排序后的结果。

 

本篇博客到此就结束啦~

如果有帮助到您的学习是我的无上荣幸!

感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6、JavaWeb-Mybatis

P116 Mybatis-入门 Mybatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发。 持久层就是三层控制中的Dao层&#xff0c;数据访问层/持久层&#xff0c; P117 Mybatis-入门-快速入门程序 步骤&#xff1a; 创建springboot工程&#xff0c;数据表和实体类 引入mybat…

【力扣 - 盛最多水的容器】

题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容…

深入理解MySQL事务:保证数据的一致性和可靠性

摘要&#xff1a;MySQL事务是一种重要的数据库管理技术&#xff0c;能够确保数据的一致性和可靠性。本文将深入探讨MySQL事务的概念、特性、隔离级别以及如何正确使用事务来处理并发访问和保护数据的问题。 一. 什么是MySQL事务&#xff1f; MySQL事务是一系列对数据库进行读写…

AI蠕虫病毒威胁升级,揭示AI安全新危机

一组研究人员成功研发出首个能够通过电子邮件客户端窃取数据、传播恶意软件以及向他人发送垃圾邮件的AI蠕虫&#xff0c;并在使用流行的大规模语言模型&#xff08;LLMs&#xff09;的测试环境中展示了其按设计功能运作的能力。基于他们的研究成果&#xff0c;研究人员向生成式…

Aigtek电压放大器选购注意事项及要求有哪些

电压放大器是电子设备中常用的一种放大器&#xff0c;广泛应用于各种电子设备和通信系统中。选购电压放大器时&#xff0c;需要考虑一些重要的注意事项和要求。下面安泰电子将为大家介绍选购电压放大器时需要注意的一些事项和要求&#xff0c;帮助您在购买过程中作出明智的决策…

Pytorch Geometric 将表格数据集(CSV 文件)转换为图形数据集

导 读 如今图数据集正在以惊人的速度出现&#xff0c;所有化学分子、社交网络和推荐系统主要以图数据结构的形式存储数据 有需要的朋友关注公众号【小Z的科研日常】&#xff0c;获取更多内容。 01、如何转换CSV文件至图形数据结构 确定图形数据所需的基本信息 节点&#xff08;…

LeetCode 刷题 [C++] 第108题.将有序数组转换为二叉搜索树

题目描述 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 题目分析 由于二叉搜索树的中序遍历是升序的&…

性能问题分析排查思路之机器(3)

本文是性能问题分析排查思路的展开内容之一&#xff0c;第2篇&#xff0c;主要分为日志1期&#xff0c;机器4期、环境2期共7篇系列文章&#xff0c;本期是第三篇&#xff0c;讲机器&#xff08;硬件&#xff09;的网络方面的排查方法和最佳实践。 主要内容如图所示&#xff1a…

Python + Selenium —— 多窗口!

首先我们先理解下什么是窗口的概念&#xff1a;浏览器的 window 概念&#xff0c;一个tab就是一个window。 什么时候会产生多窗口&#xff1a; <a target"_blank" class"cate_menu_lk" href"//jiadian.jd.com">家用电器</a>target&…

巧【二叉搜索树的最近公共祖先】【二叉搜索树的性质】Leetcode 235. 二叉搜索树的最近公共祖先

【二叉搜索树的最近公共祖先】【二叉搜索树性质】Leetcode 235. 二叉搜索树的最近公共祖先 【巧】解法1 利用二叉搜索树有序的性质解法2 采用二叉树求最近公共祖先的方法——后序遍历 ---------------&#x1f388;&#x1f388;235. 二叉搜索树的最近公共祖先 题目链接&#x…

深度学习PyTorch 之 RNN-中文多分类【代码解析】

上篇文章给出了RNN-中文多分类的代码实现&#xff0c;本次主要是对RNN的架构进行一个详细的解析 1、主代码 class RNN(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, bidirectional, dropout):super().__init__()# 初始化函数…

香杆箐骑行记,春回大地

2024年3月2日春回大地之际我们校长骑行群再次踏上征程前往香杆箐。这次骑行不仅是一次对身体的锻炼更是一次心灵的洗礼。 清晨的阳光洒满大地我们从郊野公园后门出发踏上了前往香杆箐的道路。沿途的风景如画绿树成荫鲜花盛开让人心旷神怡。我们沿着山路蜿蜒前行感受着大自然的韵…