算法学习笔记——sort 和 qsort 提供的快速排序
这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助。
从排序开始
基本的排序算法包括冒泡排序、插入排序、选择排序和快速排序的算法原理从基础的数据结构教程中即可学习,不在本文的讨论范围之内。这里主要介绍的是在算法设计程序中可以直接利用的排序工具。C/C++ 为使用者提供了标准的快速排序算法以供使用,在实际的算法设计中,使用者可以通过简单的函数调用实现排序功能。具体而言,C 实现了 qsort 函数提供排序功能,而 C++ 则提供 sort 供用户使用。
sort
sort 为 C++ 标准模版库实现的提供排序功能的函数模版。在使用时,需要包含头文件 <algorithm> ,并声明 C++ 的标准命名空间 std.
#include <algorithm>
using namespace std; //使用 sort 需要包含对应的头文件,并使用命名空间 std
在实际使用 sort 时,主要通过以下两种参数形式来调用 sort 提供的排序功能。sort 实现的快速排序算法的时间复杂度为O(nlogn).
sort( start , end ) //对 start 至 end 之间的数据排序,其中,处理的数据包括 start 而不包括 end
sort( start , end , cmp) //使用自定义的排序规则 cmp 对 start 和 end 之间的数据排序
其中 start 为待排序的数据的第一个元素的起始地址,end 为待排序的数据的最后一个元素的地址的下一个地址( 注意不是尾元素的地址 )。当使用第一种形式时,默认对待排序的元素进行升序排列。
例: int a[5] 为一个包含有 5 个 int 数据的数组,调用 sort( a , a + 5 ) 对数组 a 进行排序,则数组 a 中的元素将按照升序排列。这里注意,排序数据的第一个元素的地址为 a ,最后一个元素的地址为 a + 4 ,调用 sort 时 end 参数应该为最后一个元素地址的下一位也就是 a + 5.
sort 的第一种调用方式可以对 c++ 支持的基础数据类型进行排序。使用者也可以通过第二种形式来调用 sort ,通过 cmp 来指定排序的规则,从而对自定义的数据结构体进行排序。cmp 函数使用两个待排序的数据作为参数,并返回一个 bool 类型的值,当 返回值为 true 时,则将作为参数的第二个数据排在第一个数据前面。cmp 的大致结构如下所示。
bool cmp( type a , type b )
{
判断规则 //当 cmp 函数返回 true 时,则将数据 b 排在数据 a 的前面
}
例:对于一个自定义的学生的数据结构类型,其为一个包含有准考证、姓名和分数信息,要求对包含有学生数据的数组进行排序,使得学生按分数从高到低,分数一致时按准考证号从低到高排序。学生结构的定义如下所示。
typedef struct{
int sno;
int score;
char name[];
}Student;
则根据上述排序规则和学生数据结构的信息,可以编写一个 cmp 函数定义 sort 的比较规则。这里注意,C++ 的比较运算符会根据比较结果返回逻辑值 True 或 False.
bool cmp( Student a , Student b )
{
if( a.score != b.score )
return a.score < b.score ; // b 的分数比 a 高时,返回值为 true ,此时将 b 排在 a 前面
elsereturn a.sno > b.sno ; // b 的学号比 a 低时,返回值为 true,此时将 b 排在 a 前面
}
对一个包含有 100 个学生信息的数组 Student a[ 100 ] 进行排序,则只需通过 sort( a , a + 100 , cmp ) 调用即可。
注: sort 的第一种调用形式实际是使用 < 运算符对待排序数据进行比较和排序( 小者在前 ),故而若使用者为自定义的数据结构定义了 < 运算符,则也可以直接使用 sort 的第一种形式进行排序。
qsort
qsort 为 C 语言标准库提供的快速排序算法接口,在使用时需要包括 C 标准库 stdio.h 或 C++ 库 cstdlib 。相比于 C++ 提供的 sort ,qsort 由于涉及更多的指针操作在使用时相对而言更加复杂。qsort 函数的函数原型如下所示。
void qsort (void* base, size_t num, size_t size, //base 为比较元素的起始地址,num 为待比较元素的个数,size 为单个待比较元素占用的字节长度
int (*compar)(const void*,const void*)); //compar 为函数指针,用于规定元素比较规则
在使用 qsort 函数时,待比较数据的起始位置 base 、待比较数据的数量 num 和单个数据所占用的字节数 size 共同指定了待比较数据所在区域。而函数指针 compar 则指定了如何对上述区域中的元素进行比较。
这里主要介绍下比较函数 compar 的写法。如 qsort 的函数原型所示,函数 compar 使用两个 void * 指针作为参数,故而在函数内部进行元素比较时,需要对上述指针进行类型转换以符合原始比较数据的类型格式,函数的返回值为 int 类型,函数返回值小于 0 时,将第一个参数放置在第二个参数前面,返回值大于 0 时,将第一个参数放置在第二个参数后面。下面以 sort 中的排序要求实现使用 qsort 时所需的具体的排序函数。注意 C 语言的比较运算符返回值为 0 和 1 ,和上述比较函数要求返回的正值和负值略有不同,可以使用 exp1? exp2 : exp3 形式的方式简化程序。
int compareStudent( const void *a , const void *b )
{
if( ( Student * ) a -> socre != ( Student * ) b -> score )
return ( ( Student * ) a -> socre > ( Student * ) b -> score ) ? : ;
else
return ( ( Student * ) a -> sno < ( Student * ) b -> sno ) ? : ;
}
在定义好比较函数后,以 sort 中的情况为例,调用的方式 qsort 函数的方式如下所示。
qsort( a , 100 , sizeof( Student ) , compareStudent ); //使用 compar 函数对一百个学生的数据进行排序
另注:虽然 C 和 C++ 为用户提供了方便快捷的快速排序接口,但在实际的算法学习过程中,理解算法的原理和享受算法所带来的方便一样重要。故而除了学习上述接口的使用外,也应该了解和掌握基础的排序算法的原理和具体实现,让自己不局限于做一个仅会使用别人提供的工具的人,自勉。
参考:
算法笔记 p235-242
王道论坛计算机考研机试指南 - 2.1 排序
算法学习笔记——sort 和 qsort 提供的快速排序的更多相关文章
- 并发编程学习笔记(4)----jdk5中提供的原子类及Lock使用及原理
(1)jdk中原子类的使用: jdk5中提供了很多原子类,它会使变量的操作变成原子性的. 原子性:原子性指的是一个操作是不可中断的,即使是在多个线程一起操作的情况下,一个操作一旦开始,就不会被其他线程 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- R语言实现关联规则与推荐算法(学习笔记)
R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...
- 二次剩余Cipolla算法学习笔记
对于同余式 \[x^2 \equiv n \pmod p\] 若对于给定的\(n, P\),存在\(x\)满足上面的式子,则乘\(n\)在模\(p\)意义下是二次剩余,否则为非二次剩余 我们需要计算的 ...
- Python—kmeans算法学习笔记
一. 什么是聚类 聚类简单的说就是要把一个文档集合根据文档的相似性把文档分成若干类,但是究竟分成多少类,这个要取决于文档集合里文档自身的性质.下面这个图就是一个简单的例子,我们可以把不同的文档聚合 ...
随机推荐
- PHP正则匹配网址
/** * @param $url 网址 * @return bool */ public static function checkUrl($url){ $pattern="/^(http ...
- python的JSON库
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写. 1.json库的使用 使用 JSON 函数需要导入 json 库:import jso ...
- AQS工作原理分析
AQS工作原理分析 一.大致介绍1.前面章节讲解了一下CAS,简单讲就是cmpxchg+lock的原子操作:2.而在谈到并发操作里面,我们不得不谈到AQS,JDK的源码里面好多并发的类都是通过Sy ...
- (三)Django继承AbstractUser新建User Model时出现fields.E304错误
错误详情: auth.User.groups: (fields.E304) Reverse accessor for ‘User.groups’ clashes with reverse access ...
- 『Andrew and Chemistry 树同构』
Andrew and Chemistry Description During the chemistry lesson Andrew learned that the saturated hydro ...
- springboot初体验-不知道怎么创建spring-boot项目?
https://spring.io/projects/spring-boot/ 在以上地址找到 Quick start Bootstrap your application with Spring I ...
- Django model distinct 的使用方法
原文: 今天突然有人问起在 django 的 model 里面怎么用 distinct, 对于这种东西,我一向的观点是查看django 的在线文档.于是不加思索的根据在线文档给出了答案,但结果很让人沮 ...
- linux环境:FTP服务器搭建
转载及参考至:https://www.linuxprobe.com/chapter-11.html https://www.cnblogs.com/lxwphp/p/8916664.html 感谢原作 ...
- SSM之Mybatis整合及使用
SSM 在ss基础上加进行整合Mybatis(applicationContext.xml中添加配置),并添加分页拦截器(添加mybatis分页拦截器),并用generator动态生成到层. 构建基础 ...
- VC 在桌面上绘制一些图形
注意:这是在桌面上绘制图形.如果想在VC++ MFC工程的视窗口上绘制图形.可以这么来,在工程View类的一个菜单响应(或者鼠标单击等事件的的响应)函数中添加下面main 中的代码,只需要将“红色字体 ...