【C++STL】快速排序算法(sort)的原理与使用

2023-11-01

一、sort算法原理

std::sort 是 C++ 标准库中提供的排序算法,它使用的是一种经典的排序算法——快速排序(Quicksort)或者是其变种。

快速排序是一种基于比较的排序算法,通过不断地选择一个基准值(pivot),将待排序序列分割为两个子序列,其中一个子序列的所有元素小于等于基准值,另一个子序列的所有元素大于基准值。然后递归地对两个子序列进行排序,最终得到有序序列。

std::sort 在实现快速排序时,通常会结合其他优化技巧,如插入排序或堆排序,以提高算法的性能和效率。

快速排序的基本步骤:

  1. 选择一个基准值(pivot)。可以选择序列的第一个元素、最后一个元素、中间元素或者随机选择一个元素作为基准值。
  2. 将序列分割为两个子序列,使得一个子序列的所有元素小于等于基准值,另一个子序列的所有元素大于基准值。
  3. 递归地对两个子序列进行排序,即对小于等于基准值的子序列和大于基准值的子序列进行排序。
  4. 合并两个排序好的子序列,得到最终的有序序列。

快速排序是一种原地排序算法,它的平均时间复杂度为 O(nlogn),其中 n 是待排序序列的大小。在最坏情况下,快速排序的时间复杂度为 O(n^2),但通过合理选择基准值可以减少最坏情况的发生概率。

std::sort 的实现会考虑到不同情况下的性能和效率,并且在不同的编译器和库实现中可能有所不同。它通常会根据序列的大小、数据类型以及其他因素来选择合适的排序算法,以获得更好的性能。对于小型序列,std::sort 可能会使用插入排序或者其他简单的排序算法,而对于大型序列,它通常会采用快速排序或者其变种。此外,std::sort 还可以接受自定义的比较函数谓词,以满足不同的排序需求。

二、sort算法使用

功能: 对容器内元素进行排列(默认升序排列)

  • sort()属于质变算法
函数原型: sort(iterator beg, iterator end, pred) 解释
参数1 iterator beg 开始迭代器
参数2 iterator end 结束迭代器
参数3 pred 谓词

详细信息:

当调用 std::sort 进行排序时,它采用的是一种分治策略的快速排序算法,这意味着它将待排序的元素分割成较小的子集,然后对这些子集进行排序并逐步合并,最终得到完全排序的结果。

  • 排序范围:std::sort 排序的是一个范围,由两个迭代器 firstlast 指定,表示排序的起始位置和结束位置。排序将应用于 [first, last) 区间内的元素。
  • 排序准则: 默认情况下,std::sort 使用 < 运算符进行比较来确定元素的顺序。如果要按照其他准则进行排序,可以提供自定义的比较函数或函数对象作为可选的第三个参数。这个比较函数或函数对象应接受两个参数,并返回一个布尔值,指示第一个参数是否在排序中应排在第二个参数之前。
  • 时间复杂度:std::sort 使用快速排序算法,其平均时间复杂度为 O(n log n),其中 n 是要排序的元素的数量。在最坏情况下,快速排序的时间复杂度为 O(n^2),但这种情况很少发生。
  • 容器要求:std::sort 可以用于标准容器(如 std::vectorstd::dequestd::list 等)以及普通的数组。排序会就地进行,即直接修改容器中的元素顺序,而不会创建新的容器。
  • 可自定义类型:std::sort 不仅可以对基本类型(如整数、浮点数)进行排序,还可以对自定义类型进行排序,只要自定义类型支持比较操作符 < 或提供自定义的比较函数。
  • 迭代器失效:std::sort 不会使迭代器失效,这意味着在排序后仍然可以使用原始容器的迭代器。
  • 稳定性:std::sort 不保证排序的稳定性,即相等元素的顺序可能在排序后发生改变。如果需要保持相等元素的顺序不变,可以使用 std::stable_sort 算法。

示例1: 默认情况下为升序排列

#include <iostream>
#include <algorithm> //必须包含该头文件
#include <vector>
using namespace std;

//函数对象(仿函数)
class print
{
public:
	void operator()(int value)
	{
		cout << value << " ";
	}
};

void test01()
{
	vector<int> vec = {6, 9, 3, 4, 2, 7, 1, 5, 8};

	//排序前
	cout << "排序前:";
	for_each(vec.begin(), vec.end(), print());
	cout << endl;

	//排序后-升序
	cout << "排序后:";
	sort(vec.begin(), vec.end());   //默认升序
	for_each(vec.begin(), vec.end(), print());
	cout << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
排序前:6 9 3 4 2 7 1 5 8
排序后:1 2 3 4 5 6 7 8 9

示例2: 使用谓词std::greater<>

  • greater<> 是一个模板类,它是一个二元谓词(binary predicate),用于比较两个值的大小关系。
#include <iostream>
#include <algorithm> //必须包含该头文件
#include <vector>
using namespace std;

//函数对象(仿函数)
class print
{
public:
	void operator()(int value)
	{
		cout << value << " ";
	}
};

void test01()
{
	vector<int> vec = {6, 9, 3, 4, 2, 7, 1, 5, 8};

	//排序前
	cout << "排序前:";
	for_each(vec.begin(), vec.end(), print());
	cout << endl;

	//排序后-降序-添加谓词greater
	cout << "排序后:";
	sort(vec.begin(), vec.end(), greater<int>());
	for_each(vec.begin(), vec.end(), print());
	cout << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
排序前:6 9 3 4 2 7 1 5 8
排序后:9 8 7 6 5 4 3 2 1

示例3: 自定义类型排序

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

class goods
{
public:
    goods(string name, int price)
    {
        m_name = name;
        m_price = price;
    }

public:
    string m_name;
    int m_price;
};

// 自定义排序-根据商品价格升序
struct arrange
{
    bool operator()(const goods& value1, const goods& value2)
    {
        return value1.m_price < value2.m_price;
    }
};

class print
{
public:
    void operator()(const goods& value)
    {
        cout << "名称:" << value.m_name  << "\t价格:" << value.m_price << endl;
    }
};

void test01()
{
    goods goods1("可乐", 3);
    goods goods2("红牛", 5);
    goods goods3("脉动", 4);
    goods goods4("外星人", 6);
    goods goods5("雪碧", 3);
    goods goods6("哇哈哈", 2);

    vector<goods> vec;
    vec.push_back(goods1);
    vec.push_back(goods2);
    vec.push_back(goods3);
    vec.push_back(goods4);
    vec.push_back(goods5);
    vec.push_back(goods6);

    // 排序前
    cout << "排序前:" << endl;
    for_each(vec.begin(), vec.end(), print());
    cout << endl;

    // 排序后-升序-添加谓词arrange
    cout << "排序后:" << endl;
    sort(vec.begin(), vec.end(), arrange());
    for_each(vec.begin(), vec.end(), print());
    cout << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}
//result
排序前:
名称:可乐      价格:3
名称:红牛      价格:5
名称:脉动      价格:4
名称:外星人    价格:6
名称:雪碧      价格:3
名称:哇哈哈    价格:2

排序后:
名称:哇哈哈    价格:2
名称:可乐      价格:3
名称:雪碧      价格:3
名称:脉动      价格:4
名称:红牛      价格:5
名称:外星人    价格:6

总结:std::sort 是一个高效、通用且灵活的排序算法。它在大多数情况下都能提供良好的性能,并且可以应用于不同类型的容器和自定义类型。然而,对于一些特殊需求,例如需要稳定排序或对大型容器进行排序,可能需要选择其他排序算法或使用自定义的排序实现。


如果这篇文章对你有所帮助,渴望获得你的一个点赞!

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++STL】快速排序算法(sort)的原理与使用 的相关文章

随机推荐

  • 2022全年度净水器十大热门品牌销量榜单

    随着人们健康意识的提升 每天喝足量水的观念已经深入人心 而伴随居民生活水平的提高 当下居民对水污染问题也更加关注 对饮水品质的认知和要求也随之升级 因此 净水器在过去几年开启了高速增长的趋势 根据鲸参谋数据显示 2022年京东平台净水器的年
  • docker具名挂载与匿名挂载

    文章分为三部分 什么是具名 匿名和指定路径挂载 匿名挂载 具名挂载 什么是具名 匿名和指定路径挂载 v 容器内路径 匿名挂载 v 卷名 容器内路径 具名挂载 v 宿主机路径 容器内路径 指定路径挂载 拓展 宿主机路径 容器内路径 ro 只读
  • 好书推荐计划:Keras之父作品《Python 深度学习》

    大家好 我禅师的助理兼人工智能排版住手助手条子 可能很多人都不知道我 因为我真的难得露面一次 天天给禅师做底层工作 今天条子终于也熬到这一天 终于也有机会来为大家写文章了 激动的我啊 都忘了9月17号中午和禅师在我厂门口兰州料理吃饭 禅师要
  • C++——关于返回值优化问题

    我们知道 对于一个函数的返回值来说 其是一个对象的拷贝 并且应当是一个右值 我们现在有一个函数 A get A A a 1 return a int mian A get A return 0 这个函数的行为应当是在函数体中构造一个a 然后
  • 浅析React Router V6 useRoutes的使用

    本篇文章记录了useRoutes第一个参数的使用方法 暂不涉及第二个参数 文章目录 一 使用位置 二 嵌套路由 三 分模块管理 注意事项 一 使用位置 一开始以为可以像react router config那样使用 于是写成 import
  • 用 construct 2 制作简易弹幕游戏

    用 construct 2 制作简易弹幕游戏 1 打开construct 2 加入背景 3 建立新的图层 4 在新的图层里加入素材 超人 弹幕 4 加入鼠标 5 给超人和弹幕设置动作 超人的 弹幕的 6 加入文字框 7 编写代码 完成啦
  • TCP/UDP报文格式及各种通信机制简介

    TCP UDP报文格式及各种通信机制简介 一 UDP报文 二 TCP报文 三 TCP通信机制 1 确认应答机制 2 超时重传机制 3 滑动窗口及快重传机制 4 流量控制 5 拥塞控制及慢启动机制 6 延迟应答 7 捎带应答 8 粘包问题 一
  • PLC中的定时器

    1 脉冲定时器 将指令列表中的 生成脉冲 指令TP拖放到梯形图中 在出现的 调用选项 对话框中 将默认的背景数据块的名称改为T1 可以用它来做定时器的标示符 单击 确定 按钮 自动生成背景数据块 定时器的输入IN为启动输入端 PT为预设时间
  • 二叉搜索树的概念 及 功能代码实现

    1 概念 二叉搜索树 又称 二叉排序树 特点 二叉树 每个节点中保存关键字 key 关键字需要具备 比较 的能力 每个节点 都是 大于左子树 小于右子树 二叉树搜索树中 不会出现 相等的 key 中序遍历 一定是 有序的 时间复杂度 最好和
  • 利用Hbuilder将Vue项目打包成apk

    一 配置config index js 本人没有配置index js文件 就开始进行了打包 结果最终效果是页面空白 解决了空白 接着底部图标 我是用的阿里巴巴图片 资源找不到 所以配置这步比较重要 1 页面空白的解决 打开config in
  • uboot2014移植到QT2440

    http bbs chinaunix net thread 4143968 1 1 html
  • Kotlin 协程(Coroutines)配合使用 Retrofit,网络请求

    第一步 添加所需依赖 管理生命周期 implementation androidx lifecycle lifecycle livedata ktx 2 2 0 implementation androidx lifecycle lifec
  • K-近邻法(KNN算法)

    1 kNN算法 K 最近邻 k Nearest Neighbors 描述 简单地说 k 近邻算法采用测量不同特征值之间的距离方法进行分类 k 近邻算法 是一种基本 分类与回归 方法 它是是 监督学习 中分类方法的一种 属于 懒散学习法 惰性
  • 【实验四】【使用Select 语句查询数据】

    文章目录 数据 一 简单查询 二 汇总查询 三 连接查询和子查询 数据 这里为了体现查询语句的效果 下面根据查询语句的要求设计数据 结果如下 KC表 XSQK表 XS KC表 打开 SQL Server Management Studio
  • 【数据结构与算法】--二叉树OJ题

    单值二叉树 如果二叉树每个节点都具有相同的值 那么该二叉树就是单值二叉树 只有给定的树是单值二叉树时 才返回 true 否则返回 false 示例 1 输入 1 1 1 1 1 null 1 输出 true 示例 2 输入 2 2 2 5
  • 【C语言技巧】滑动滤波算法滤除抖动

    简易滑动滤波算法 算法原理 将新数据放入到数组的最后 每次在得到数据之前先将数据左移一个元素 踢掉第一个元素最旧的数据 最后数组计算平均 include
  • 解决adb push时出现的“Read-only file system“问题

    出现Read only file system问题 不是因为文件或者文件夹的权限不对 而是要push的目录对应的分区是以只读方式挂载的 网上给出的解决办法是重新以读写方式挂载对应分区 以 system分区为例 使用命令 mount o re
  • 手写数字识别画板前后端实现

    1 系统概要 手写数字识别画板系统 按照MVC原则开发 主要由两部分组成 交互界面 视图View 部分是传统的HTML CSS JS网页 这同样也是一种遵循MVC开发方式 手写数字识别部分 模型Model 是使用Python开发的深度学习的
  • 【网络原理】传输层重点协议 TCP与UDP协议详解

    文章目录 一 UDP协议 1 UDP特点 2 UDP协议报文格式 3 基于UDP的应用层协议 4 关于UDP协议的一个拓展问题 经典面试题 二 TCP协议 1 TCP协议报文格式 2 TCP原理 1 确认应答机制 安全机制 2 超时重传机制
  • 【C++STL】快速排序算法(sort)的原理与使用

    一 sort算法原理 std sort 是 C 标准库中提供的排序算法 它使用的是一种经典的排序算法 快速排序 Quicksort 或者是其变种 快速排序是一种基于比较的排序算法 通过不断地选择一个基准值 pivot 将待排序序列分割为两个