快速排序和qsort函数详解详解qsort函数

  💕是非成败转头空,青山依旧在,几度夕阳红💕

作者:Mylvzi 

 文章主要内容:快速排序和qsort函数详解 

前言:

我们之前学习过冒泡排序,冒泡排序尽管很方便,但也存在一些局限性,冒泡排序只能排序整型数据,对于浮点型的数据以及结构体数据的排序无能为力,但是在C语言的库中,有一个库函数能够实现这样的排序-->qsort函数 

qsort函数其实是一种基于快速排序的算法,其时间复杂度为O(N*logN),下面带大家了解一下快速排序算法:

一.快速排序:QuickSort 

分析: 

 可以知道,快速排序的核心在于“分区操作”,即每次都要根据基准元素进行分区;

代码实现:

//QuickSort  排序  的实现
//找基准元素,分区,递归,合并//交换函数
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}//分割函数:以基准元素为轴,分而治之
int Partition(int arr[], int left, int right)//返回值:基准元素的下标
{//设置默认基准元素int pivot = arr[right];int i = left-1;//将小于基准元素的值放在左边,i是左子数组的下标//遍历数组,移动元素for (int j = left; j <= right; j++){if (arr[j] < pivot)//小于,就放到左边,交换值{i++;Swap(&arr[i], &arr[j]);}}//将基准元素置于轴Swap(&arr[i + 1], &arr[right]);return i + 1;
}void QuickSort(int arr[], int left, int right)//left左下标  right右下标
{if (left < right){//找到基准元素的下标int PivotIndex = Partition(arr, left, right);//对左子数组进行递归分区QuickSort(arr, left, PivotIndex - 1);//对右子数组进行递归分区QuickSort(arr, PivotIndex + 1, right);}}int main()
{int arr[] = { 6, 3, 8, 5, 2, 7, 4 };int n = sizeof(arr) / sizeof(arr[0]);//打印原数组printf("Original array: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}// 调用快速排序函数对数组进行排序QuickSort(arr, 0, n-1);//打印排序之后的数组printf("\nSorted array: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}return 0;
}

验证:

 

优化QuickSort: 

优化一:

缺陷:选取的pivot如果是整个序列的中间值,在第一次partition之后,会得到一个较为平均的分区,处理这样的分区更加简单,效率更高(处理4 4比处理1 8更简单)

解决方法:利用三数取中法使我的pivot是中间值的概率更高

得到数组左中右下标的数据,使pivot为中间值

    //设置默认基准元素int pivot;//优化一:三数取中法优化pivot的取值(处理4 4比处理1 8简单)//不能固定取同一位置的元素为pivotint m = left+ (right - left) / 2;if (arr[left] < arr[right])//保证右边元素较小{Swap(&arr[left], &arr[right]);}if (arr[left] < arr[m])//保证中间元素较小{Swap(&arr[m], &arr[right]);}if (arr[m] > arr[right])//保证右边元素是中间值{Swap(&arr[m], &arr[left]);}pivot = arr[right];//将左中右三个元素的中间值赋给pivot

 

二.基于快速排序的函数-->qsort函数

原型:

代码1:比较整形数据 

//qsort函数
//快速的排序算法,适用于不同的数据类型
//void qsort(
//	void* base,//需要被排序的数组(首地址)
//	size_t num,//数组元素个数
//	size_t size,//元素类型大小
//	int(*cmp)(const void* ptr1, const void* ptr2)//比较函数
//	//ptr1 >ptr2 返回>0  交换位置  默认是升序排序的
//);//利用qsort函数进行冒泡排序
int cmp_int(const void* ptr1, const void* ptr2)
{//默认是升序排序的//结果>0,就会交换位置return (*(int*)ptr1 - *(int*)ptr2);//降序-->添加负号/*return -(*(int*)ptr1 - *(int*)ptr2);*/
}int main()
{int arr[6] = { 4,25,6,78,534,94 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, 6, sizeof(arr[0]), cmp_int);//打印输出排序后的数组int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

 代码2:比较结构体数据

typedef struct Stu
{char name[20];int age;
}Stu;/*按年龄排序*/
int cmp_by_stu_age(const void* ptr1, const void* ptr2)
{return ((struct Stu*)ptr1)->age - ((struct Stu*)ptr2)->age;
}void test()
{Stu arr[3] = { {"zhangsan",13},{"lisi",5},{"wangwu",18} };//按年龄排序int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_by_stu_age);}/*按照姓名排序*/
int cmp_stu_by_name(const void* ptr1, const void* ptr2)
{return strcmp(((Stu*)ptr1)->name, ((Stu*)ptr2)->name);
}
void test2()
{Stu arr[3] = { {"zhangsan",13},{"lisi",5},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}//排序结构体
int main()
{//test();test2();return 0;
}

代码3:利用冒泡排序的思想模拟实现qsort函数

//利用冒泡排序的思想模拟qsort函数
//模仿qsort的参数
//未知类型数组-->void* base  -->起始地址
//元素个数-->int num
//未知类型-->int size
//比较函数-->将需要比较的数据传递给cmp函数,根据其返回值判断是否需要交换位置//如果返回值>0,就交换元素位置(一个一个字节交换)
void Swap(char* buf1, char* buf2,int size)
{int i = 0;for (i = 0; i < size; i++){int tmp = *buf1; *buf1 = *buf2; *buf2 = tmp;buf1++;buf2++;}}
void bubble_sort(void* base, int num, int size, int(*cmp)(const void* ptr1, const void* ptr2))
{//基本逻辑不变,两两比较,一次确定一个元素的位置int i = 0;//趟数  sz-1趟int j = 0;//每次需要比较的元素个数for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++)  {                                                           //初始地址if (cmp((char*)base + j * size, (char*)base + (j+1) * size) > 0)//比较的的是前后两个元素的地址的数据-->计算地址-->(char*)base+j*size-->返回值>0,就交换{//前面的元素>后面元素就交换位置Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}int main()
{int arr[6] = { 4,25,6,78,534,94 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, 6, sizeof(arr[0]), cmp_int);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

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

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

相关文章

Session与Cookie的区别(五)

储存状态的方式 小明的故事说完了&#xff0c;该来把上面这一段变成网络的实际案例了。其实在网络世界中问题也是一样的。 前面已经提到过我们会把状态存在 Cookie 里面&#xff0c;让 Request 之间能够变得有关联。 假设我们今天要来做一个会员系统&#xff0c;那我要怎么知道…

vue 列表|表格环境中的下拉菜单

elementui组件为vue提供了各式各样的ui组件&#xff0c;但均为各类最为基本的控件&#xff0c;没有提供业务级的使用案例&#xff0c;为此进行扩展补充。 vue-elementui 基本入门使用 一、下拉菜单 下拉菜单与html中的select控件有所差距&#xff0c;select为表单控件的一员页…

windows(iis)服务器部署安装wordpress(php)网站教程

该教程包含iis安装,php安装,mysql安装,php网站部署上线,windows服务部署php网站,只需要这一篇文章就够了。 该教程为iis服务器部署安装wordpress(php)网站教程,同样适用wordpress网站迁移。 配置要求 1、windows服务器安装iis windows服务器安装iis管理器 打开控制面…

项目中使用git vscode GitHubDesktopSetup-x64

一、使用git bash 1.使用git bash拉取gitee项目 1.在本地新建一个文件夹&#xff08;这个文件夹是用来存放从gitee上拉下来的项目的&#xff09; 2.在这个文件夹右键选择 git bash here 3.输入命令 git init (创建/初始化一个新的仓库) 4.输入命令 git remote add origin …

医学影像PACS临床信息系统源码

医学影像临床信息系统&#xff08;Picture Archiving and Communication Systems&#xff09;PACS是指从医疗影像设备中获得数字影像&#xff0c;利用高速网络进行存储、管理、传输的医疗影像信息管理系统。通过该系统&#xff0c;能实现影像数字化、无胶片化管理。 登记系统 …

配置Picgo图床之COS、OSS、Github图床

简介 PicGo是一款开源的图片上传和管理工具&#xff0c;它提供了简单易用的界面和丰富的功能&#xff0c;方便用户上传、管理和分享图片。 以下是PicGo的一些主要特点和功能&#xff1a; 图片上传&#xff1a;PicGo支持将本地图片快速上传到云存储服务&#xff0c;如七牛云、…

解决Vue+Element UI使用表单rules国际化时From表单验证信息不能实时更新

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 博主在工作之余开始进行自动化测试平台的开发&#xff0c;虽然已经996一个月了但是还是在使劲挤时间做这件事情&#xff0c;目前平台使用前端框架vu…

LangChain手记 Overview

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Overview 综述&#xff08;Overview&#xff09; LangChain是为大模型应用开发设计的开源框架 LangChain目前提供Python和JavaScript&#xff08;TypeScript&#xff09;两种语言的包 LangChain的主攻方向是聚合和…

扩散模型实战(三):扩散模型的应用

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散只是一种思想&#xff0c;扩散模型也并非固定的深度网络结构。除此之外&#xff0c;如果将扩散的思想融入…

docker solr-8.11.2安装部署

历史背景 现在solr官网仅能够下载到最新版本的安装包。并且支持docker。现在就用docker来部署一下 1、准备工作 docker环境部署&#xff08;这个自己百度一下哈&#xff0c;很简单两个命令就能解决&#xff09; yum -y install yum-utils yum -y install docker-ce 安装命令…

第7集丨Vue 江湖 —— 条件渲染

目录 一、v-show二、v-if2.1 基本使用2.2 条件渲染分组2.3 与 v-else-if、v-else 结合使用 三、v-if vs v-show四、测试案例 本节条件渲染所涉及到的指令有&#xff1a; v-showv-ifv-else-ifv-else 一、v-show 1. 用法&#xff1a; 语法: v-show" 表达式"&#xff…

FFmpeg 使用总结

FFmpeg 简介 FFmpeg的名称来自MPEG视频编码标准&#xff0c;前面的“FF”代表“Fast Forward”&#xff0c;FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。可以轻易地实现多种视频格式之间的相互转换。包括如下几个部分&#xf…

webpack基础知识九:如何提高webpack的构建速度?

一、背景 随着我们的项目涉及到页面越来越多&#xff0c;功能和业务代码也会随着越多&#xff0c;相应的 webpack 的构建时间也会越来越久 构建时间与我们日常开发效率密切相关&#xff0c;当我们本地开发启动 devServer 或者 build 的时候&#xff0c;如果时间过长&#xff…

电源控制--品质因素Q值全解

什么是品质因素Q值&#xff1f; 在电源控制中&#xff0c;品质因素 Q 值通常用于描述电源滤波器的性能。电源滤波器用于减小电源中的噪声和干扰&#xff0c;以提供干净稳定的电源供应给电子设备。 品质因素 Q 值在电源滤波器中表示滤波器的带宽和中心频率之比&#xff0c;用于…

IP提取器对比器

需求&#xff1a; 一个html 页面 &#xff0c;有两个输入框 第一个输入框输入文本中包含多个ip&#xff0c;输入的ip是不规则的&#xff0c;需要使用正则表达式提取出 输入文本的ip地址 &#xff0c; 然后在第二个输入框中输入内容&#xff0c;并提取出内容的ip &#xff0c;如…

什么是OCR?OCR技术详解

光学字符识别(Optical Character Recognition)简称为“OCR”。ORC是指对包含文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的技术。 一般包括以下几个过程&#xff1a; 1.图像输入 针对不同格式的图像&#xff0c;有着不同的存储格式和压缩方式。目前&…

Elastic:linux设置elasticsearch、kibana开机自启

0. 引言 每次启动服务器都要手动启动es服务&#xff0c;相当之不方便&#xff0c;为此&#xff0c;书写一个脚本&#xff0c;实现es、kibana的开机自启 1. 原理 首先任何服务要实现开机自启&#xff0c;都可分为如下三步&#xff1a; 1、在/etc/init.d目录下创建启动、关闭服…

海康威视摄像头配置RTSP协议访问、onvif协议接入、二次开发SDK接入

一、准备工作 (1)拿到摄像头之后,将摄像头电源线插好,再将网线插入到路由器上。 (2)将自己的笔记本电脑也连接到路由器网络,与摄像头出在同一个局域网。 二、配置摄像头 2.1 激活方式选择 第一次使用设备需要激活,在进行配置。 最简单,最方便的方式是选择浏览器激…

uniapp创建项目入门【详细】

大家在学习vue和微信小程序之后&#xff0c;就可以开始来学习uniapp了&#xff0c;在uniapp中&#xff0c;一套代码可以跨越所有的平台&#xff0c;可以很方便的维护。接下来我们先来学习如何创建uinapp的项目 一、uniapp的创建需求 大家只要会vue和微信小程序的基础来学习unia…

浅析 String

浅析String 一、创建字符串二、字符串与常量池三、字符串的不可变性四、字符串的拼接五、StringBuilder和StringBuffer 一、创建字符串 //三种常用的构造字符串的方式public static void main(String[] args) {String str1 "hello";String str2 new String("w…