超详细解析C++实现快速排序算法的方法

目录
  • 一、前言
    • 1.分治算法
    • 2.分治算法解题方法
  • 二、快速排序
    • 1.问题分析
    • 2.算法设计
    • 3.算法分析
  • 三、AC代码

一、前言

1.分治算法

快速排序,其实是一种分治算法,那么在了解快速排序之前,我们先来看看什么是分治算法。在算法设计中,我们引入分而治之的策略,称为分治算法,其本质就是将一个大规模的问题分解为若干个规模较小的相同子问题,分而治之。

2.分治算法解题方法

1.分解:

将要解决的问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题。

2.治理:

求解各个子问题。由于各个子问题与原问题形式相同,只是规模较小而已,而当子问题划分得足够小时,就可以用简单的方法解决。

3.合并:

按原问题的要求,将子问题的解逐层合并构成原问题的解。

二、快速排序

1.问题分析

快速排序是比较快的排序方法。它的基本思想是通过一组排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据小,然后再按此方法对这两部分数据进行快速排序,整个排序过程可以递归进行,以此使所有数据变成有序序列。

2.算法设计

(1)分解:

先从数列中取出一个元素作为基准元素。一基准元素为标准,将问题分解为两个子序列,使小于或者等于基准元素的子序列在左侧,使大于基准元素的子序列在右侧。

(2)治理 :

对两个子序列进行快速排序(递归快速排序)。

(3)合并:

将排好的两个子序列合并在一起,得到原问题的解。

(4)基准元素的选取:

①:取第一个元素。(通常选取第一个元素)

②:取最后一个元素

③:取中间位置的元素

④:取第一个、最后一个、中间位置元素三者之中位数

⑤:取第一个和最后一个之间位置的随机数 k (low<=k<=hight)

3.算法分析

假设当前的待排序的序列为 R[low,hight] , 其中 low<=hight。同时选取首元素为基准元素。

步骤一:选取首元素的第一个元素作为基准元素  pivot=R[low] ,i=low ,j=hight。

步骤二:从右向左扫描,找到小于等于 pivot 的数,如果找到,R[i] 和 R[j] 交换 ,i++。

步骤三:从左向右扫描,找到大于 pivot 的数,如果找到,R[i] 和 R[j] 交换,j--。

步骤四:重复 步骤二~步骤三,直到  j 与 i 的指针重合 返回位置 mid=i ,该位置的数正好是 pivot 元素。

至此换成一趟排序,此时以 mid 为界线,将数据分割为两个子序列,左侧子序列都比 pivot 数小,右侧子序列都比 pivot 数大,然后再分别对这两个子序列进行快速排序。

下面我将以序列(30,24,5,58,18,36,12,42,39)为例,进行图解。

(1)初始化。i=low ,j=hight,pivot=R[low]=30。如下图所示:

(2)向左走,从数组的右边位置向左找,一直找到小于等于 pivot 的数,找到R[j]=12,R[i]与R[j]交换,i++。如下图所示:

(3)向右走,从数组的左边位置向右找,一直找到比 pivot 大的数,找到 R[i]=58 ,R[i] 与 R[j] 交换 ,j--。

(4)向左走,从数组的右边位置向左找,一直找到小于等于 pivot 的数,找到R[j]=18,R[i]与R[j]交换,i++。如下图所示:

(5)向右走,从数组的左边位置向右找,一直找到比 pivot 大的数,这是 i=j,第一轮排序结束,返回 i 的位置,mid=i 。以上的操作是对序列进行分解,其代码如下图所示:

int part(int* r, int low, int hight)  //划分函数
{
	int i = low, j = hight, pivot = r[low]; //基准元素
	while (i < j)
	{
		while (i<j && r[j]>pivot) //从右向左开始找一个 小于等于 pivot的数值
		{
			j--;
		}
		if (i < j)
		{
			swap(r[i++], r[j]);  //r[i]和r[j]交换后 i 向右移动一位
		}
		while (i < j && r[i] <= pivot) //从左向右开始找一个 大于 pivot的数值
		{
			i++;
		}
		if (i < j)
		{
			swap(r[i], r[j--]);  //r[i]和r[j]交换后 i 向左移动一位
		}
	}
	return i;  //返回最终划分完成后基准元素所在的位置
}

(6)然后在分别对这两个序列(12,24,5,18)和(36,58,42,39)进行快速排序(递归)。其代码如下图所示:

void Quicksort(int* r, int low, int hight)
{
	int mid;
	if (low < hight)
	{
		mid = part(r, low, hight);  // 返回基准元素位置
		Quicksort(r, low, mid - 1); // 左区间递归快速排序
		Quicksort(r, mid+1, hight); // 右区间递归快速排序
	}
}

三、AC代码

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
int part(int* r, int low, int hight)  //划分函数
{
    int i = low, j = hight, pivot = r[low]; //基准元素
    while (i < j)
    {
        while (i<j && r[j]>pivot) //从右向左开始找一个 小于等于 pivot的数值
        {
            j--;
        }
        if (i < j)
        {
            swap(r[i++], r[j]);  //r[i]和r[j]交换后 i 向右移动一位
        }
        while (i < j && r[i] <= pivot) //从左向右开始找一个 大于 pivot的数值
        {
            i++;
        }
        if (i < j)
        {
            swap(r[i], r[j--]);  //r[i]和r[j]交换后 i 向左移动一位
        }
    }
    return i;  //返回最终划分完成后基准元素所在的位置
}
void Quicksort(int* r, int low, int hight)
{
    int mid;
    if (low < hight)
    {
        mid = part(r, low, hight);  // 返回基准元素位置
        Quicksort(r, low, mid - 1); // 左区间递归快速排序
        Quicksort(r, mid+1, hight); // 右区间递归快速排序
    }
}
int main()
{
    int a[10001];
    int  N;
    cout << "请输入要排序的数据的个数: " << endl;
    cin >> N;
    cout << "请输入要排序的数据: " << endl;
    for (int i = 0; i < N; i++)
    {
        cin >> a[i];
    }
    cout << endl;
    Quicksort(a, 0, N - 1);
    cout << "排序后的序列为: " << endl;
    for (int i = 0; i < N; i++)
    {
        cout << a[i] << " ";
    }
    cout << endl;
    return 0;
}

到此这篇关于超详细解析C++实现快速排序算法的方法的文章就介绍到这了,更多相关C++快速排序算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java C++算法题解leetcode801使序列递增的最小交换次数

    目录 题目要求 思路:状态机DP 实现一:状态机 Java C++ Rust 实现二:滚动数组 Java C++ Rust 总结 题目要求 思路:状态机DP 实现一:状态机 Java class Solution { public int minSwap(int[] nums1, int[] nums2) { int n = nums1.length; int[][] f = new int[n][2]; for (int i = 1; i < n; i++) f[i][0] = f[i][1]

  • C C++算法题解LeetCode1408数组中的字符串匹配

    目录 题目描述 整理题意 解题思路分析 优化 具体实现 复杂度分析 代码实现 暴力 暴力 + 优化 KMP 总结 题目描述 题目链接:1408. 数组中的字符串匹配 给你一个字符串数组 words ,数组中的每个字符串都可以看作是一个单词.请你按 任意 顺序返回 words 中是其他单词的子字符串的所有单词. 如果你可以删除 words[j] 最左侧和/或最右侧的若干字符得到 word[i] ,那么字符串 words[i] 就是 words[j] 的一个子字符串. 提示: 示例 1: 输入:wo

  • Java C++题解leetcode字符串轮转KMP算法详解

    目录 题目要求 思路一:双指针(模拟) Java C++ 思路二:子串 手写KMP Java dp C++ dp 调API Java C++ 总结 题目要求 思路一:双指针(模拟) Java class Solution { public boolean isFlipedString(String s1, String s2) { if (s1.length() != s2.length()) return false; int n = s1.length(); if (n == 0) retu

  • C++递归算法处理岛屿问题详解

    目录 岛屿问题定义 例题一-岛屿的数量 例题二-岛屿的周长 岛屿问题定义 岛屿问题是指用二维数组进行模拟, 1的位置表示陆地, 0的位置表示海洋.岛屿是指 被水(0)包围的陆地(1) 如下图所示: 岛屿问题是一道典型的递归问题(一位大佬曾说将岛屿问题看成是4叉树,我觉得这个比喻非常好), 对每个陆地位置, 我们需要递归地检测它的上下左右位置是不是陆地. 下面我们来写一下对岛屿问题的递归模板: public void dfs(char[][] grid, int m, int n){ // 位置越

  • C++算法实现leetcode 1252奇数值单元格数目

    目录 题目描述 整理题意 解题思路分析 具体实现 复杂度分析 代码实现 总结 题目描述 题目链接:1252. 奇数值单元格的数目 给你一个 m x n 的矩阵,最开始的时候,每个单元格中的值都是 0. 另有一个二维索引数组 indices,indices[i] = [ri, ci] 指向矩阵中的某个位置,其中 ri 和 ci 分别表示指定的行和列(从 0 开始编号). 对 indices[i] 所指向的每个位置,应同时执行下述增量操作: ri 行上的所有单元格,加 1 . ci 列上的所有单元格

  • 超详细解析C++实现快速排序算法的方法

    目录 一.前言 1.分治算法 2.分治算法解题方法 二.快速排序 1.问题分析 2.算法设计 3.算法分析 三.AC代码 一.前言 1.分治算法 快速排序,其实是一种分治算法,那么在了解快速排序之前,我们先来看看什么是分治算法.在算法设计中,我们引入分而治之的策略,称为分治算法,其本质就是将一个大规模的问题分解为若干个规模较小的相同子问题,分而治之. 2.分治算法解题方法 1.分解: 将要解决的问题分解为若干个规模较小.相互独立.与原问题形式相同的子问题. 2.治理: 求解各个子问题.由于各个子

  • 超详细解析C++实现归并排序算法

    目录 一.前言 分治算法 分治算法解题方法 二.归并排序 1.问题分析 2.算法设计 3.算法分析 三.AC代码 一.前言 分治算法 归并排序,其实就是一种分治算法 ,那么在了解归并排序之前,我们先来看看什么是分治算法.在算法设计中,我们引入分而治之的策略,称为分治算法,其本质就是将一个大规模的问题分解为若干个规模较小的相同子问题,分而治之. 分治算法解题方法 1.分解: 将要解决的问题分解为若干个规模较小.相互独立.与原问题形式相同的子问题. 2.治理: 求解各个子问题.由于各个子问题与原问题

  • Go语言单元测试超详细解析

    目录 一.单元测试分类及其概念 1.基本分类 2.细说单元测试分类 二.结合代码细说每一种测试 1.基准测试 2.组测试与子测试 三.pprof调试工具 1.对主函数进行传参 2.pprof性能调优 前言: 平时根据需求写代码.人工进行测试往往不会面面俱到,还会因为需求的改变繁琐的进行测试通过完成一个测试函数,可以大大简化测试的步骤,并且在需求该变的时候只需要改变一下测试的输入与期望 一.单元测试分类及其概念 1.基本分类 测试函数 函数前缀为Test 主要用于测试程序的一些逻辑行为是否正确 基

  • Java 超详细讲解十大排序算法面试无忧

    目录 排序算法的稳定性: 一.选择排序 二.冒泡排序 三.插入排序 四.希尔排序 五.堆排序 六.归并排序 七.快速排序 八.鸽巢排序 九.计数排序 十.基数排序 排序算法的稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,如果排序以后,保证这些记录的相对次序保持不变,即在原序列中,a[i]=a[j],且 a[i] 在 a[j] 之前,排序后保证 a[i] 仍在 a[j] 之前,则称这种排序算法是稳定的:否则称为不稳定的. 一.选择排序 每次从待排序的元素中选择最小的元素,依次

  • OneinStack一键安装PHP/JAVA/HHVM和超详细的VPS手动安装LNMP的方法

    继著名的LAMP Stack(Linux + Apache + MySQL/MariaDB + PHP)网站环境之后,LNMP Stack(Linux + Nginx + MySQL/MariaDB + PHP)以其负载小.静态文件处理能力强的优势,在Linux平台上开始流行,尤其是在配置不太高的VPS上应用广泛. 说起LNMP,多数人应该知道lnmp.org站长开发的LNMP一键安装包,该脚本虚拟主机管理.FTP用户管理.Nginx.MySQL/MariaDB.PHP的升级.常用缓存组件的安装

  • C++超详细梳理lambda和function的使用方法

    目录 lambda表达式 谈谈lambda的捕获 万能的function bind操作 lambda表达式 lambda表达式又称为匿名表达式,是C11提出的新语法.[]存储lambda表达式要捕获的值,()内的参数为形参,可供外部调用传值.lambda表达式可以直接调用 // 1 匿名调用 [](string name) { cout << "this is anonymous" << endl; cout << "hello "

  • 详解Java中使用泛型实现快速排序算法的方法

    快速排序算法概念 快速排序一般基于递归实现.其思路是这样的: 1.选定一个合适的值(理想情况中值最好,但实现中一般使用数组第一个值),称为"枢轴"(pivot). 2.基于这个值,将数组分为两部分,较小的分在左边,较大的分在右边. 3.可以肯定,如此一轮下来,这个枢轴的位置一定在最终位置上. 4.对两个子数组分别重复上述过程,直到每个数组只有一个元素. 5.排序完成. 基本实现方式: public static void quickSort(int[] arr){ qsort(arr,

  • C++带头双向循环链表超详细解析

    目录 什么是带头双向循环链表 带头双向循环链表常用接口实现 上期我们讲完了无头单向非循环链表,这期我们接着来讲链表中结构最复杂的带头双向循环链表! 本期主要内容: 什么是带头双向循环链表? 带头双向循环链表常用接口实现! 顺序表和链表的区别和联系! 什么是带头双向循环链表 什么是带头?双向?循环?(带头双向循环链表) 带头:代表链表存在一个哨兵位节点,也就是头节点,这个节点不存放任何的有效数据! 双向:每个节点都有两个指针,分别指向它的前一个节点和后一个节点! 循环:最后一个节点next不再指向

  • C++ 二叉树的实现超详细解析

    目录 1.树的概念及结构(了解) 1.1树的概念: 1.2树的表示法: 2.二叉树的概念及结构 2.1二叉树的概念: 2.2特殊的二叉树: 2.3二叉树的性质: 2.4二叉树的顺序存储: 2.5二叉树的链式存储: 3.二叉树链式结构的实现 3.1二叉树的前中后序遍历: 3.2求二叉树的节点个数: 3.3求二叉树的叶子节点个数: 3.4销毁二叉树: 1.树的概念及结构(了解) 1.1树的概念: 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合.把它叫做树是因为它看

  • C++ 栈和队列的实现超详细解析

    目录 1.栈的介绍: 2.栈的常用接口实现 3.队列的介绍 4.队列的常用接口实现 可算是把链表给结束了,很多小伙伴已经迫不及待想看到栈和队列了,那么它来了!相信有了顺序表和链表的基础,栈和队列对于你们来讲也是轻轻松松,那我就废话不多说,直接进入今天的重点: 1.栈的介绍: 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底.栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则. 压栈:栈的插入操作叫做

随机推荐