经典算法之一:快速排序

2023-05-16

快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。

总的说来,要直接默写出快速排序还是有一定难度的,因为本人就自己的理解对快速排序作了下白话解释,希望对大家理解有帮助,达到快速排序,快速搞定

 

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

该方法的基本思想是:

1.先从数列中取出一个数作为基准数。

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

 

虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。因此我的对快速排序作了进一步的说明:挖坑填数+分治法

先来看实例吧,定义下面再给出(最好能用自己的话来总结定义,这样对实现代码会有帮助)。

 

以一个数组作为示例,取区间第一个数为基准数。

0

 1 

72

57

88

60

42

83

73

48

85

初始时,i = 0;  j = 9;   X = a[i] = 72

由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。

从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++;  这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;

 

数组变为:

 1 

48

57

88

60

42

83

73

88

85

 i = 3;   j = 7;   X=72

再重复上面的步骤,先从后向前找,再从前向后找

从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;

从i开始向后找,当i=5时,由于i==j退出。

此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。

 

数组变为:

 1 

9 

48

6

57

42

60

72

83

73

88

85

可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。

上述过程详细步骤:

0:72,6,57,88,60,42,83,73,48,85,x=72

1:48,6,57,88,60,42,83,73,__,85 

2:48,6,57,__,66,42,83,73,88,85

3:48,6,57,42,66,__,83,73,88,85

3:48,6,57,42,66,__,83,73,88,85

4:48,6,57,42,66,72,83,73,88,85

经过这一轮排序后,基准数(72)左边的数都比72小,右边的都比它大,剩下的就是利用分治算法分别解决左右两边的数了。

快速排序动画演示





对挖坑填数进行总结

1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。

2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。

3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。

4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。

照着这个总结很容易实现挖坑填数的代码:

int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置
{
    int i = l, j = r;
    int x = s[l]; //s[l]即s[i]就是第一个坑
    while (i < j)
    {
        // 从右向左找小于x的数来填s[i]
        while(i < j && s[j] >= x)
            j--;
        if(i < j)
        {
            s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
            i++;
        }

        // 从左向右找大于或等于x的数来填s[j]
        while(i < j && s[i] < x)
            i++;
        if(i < j)
        {
            s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
            j--;
        }
    }
    //退出时,i等于j。将x填到这个坑中。
    s[i] = x;

    return i;
}

再写分治法的代码:

void quick_sort1(int s[], int l, int r)
{
    if (l < r)
    {
        int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[]
        quick_sort1(s, l, i - 1); // 递归调用
        quick_sort1(s, i + 1, r);
    }
}


这样的代码显然不够简洁,对其组合整理下:

//快速排序
#include <bits/stdc++.h>
using namespace std;
void P(int a[],int n)
{
    for(int i=0; i<n; i++)
        cout<<a[i]<<" ";
    cout<<endl;
}
void quick_sort(int s[], int l, int r)
{
    if (l < r)
    {
        //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
                j--;
            if(i < j)
                s[i++] = s[j];

            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;
            if(i < j)
                s[j--] = s[i];
        }
        s[i] = x;
        quick_sort(s, l, i - 1); // 递归调用
        quick_sort(s, i + 1, r);
    }
}
int main()
{
    //int a[]= {72,6,57,88,60,42,83,73,48,85};
    int a[]= {10,9,8,7,6,5,4,3,2,1};
    P(a,10);
    quick_sort(a,0,9);//注意最后一个参数是n-1!!!!!
    P(a,10);
    return 0;
}



快速排序还有很多改进版本,如随机选择基准数,区间内数据较少时直接用另的方法排序以减小递归深度。有兴趣的筒子可以再深入的研究下。

注1,有的书上是以中间的数作为基准数的,要实现这个方便非常方便,直接将中间的数和第一个数进行交换就可以了。

本文在此篇博客上做补充:

参考博客:

http://www.cnblogs.com/Braveliu/archive/2013/01/11/2857222.html

http://developer.51cto.com/art/201403/430986.htm

http://blog.csdn.net/wolinxuebin/article/details/7456330

http://www.cnblogs.com/surgewong/p/3381438.html

http://www.ruanyifeng.com/blog/2011/04/quicksort_in_javascript.html

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

经典算法之一:快速排序 的相关文章

  • 获取 Windows 操作系统的系统、网络、硬件、软件等信息

    Github 源码 xff1a WindowsInfo Net可执行文件 xff1a WindowsInfo Net exe 获取的信息 能获得的信息如下 xff08 系统 硬件 网络信息已打码 xff09 系统信息 计算机名 xff1a
  • 一个基于 C# 的简单的线程安全日志模块

    一个基于 C 的简单的线程安全日志模块 xff0c 它使用生产者 消费者模式 xff0c 可以在 NET Framework 和 Net Core 中使用 Github 地址 xff1a LogConsumer 使用 将 LogConsum
  • Python爬虫深造篇(一)——多线程网页爬取

    一 前情提要 相信来看这篇深造爬虫文章的同学 xff0c 大部分已经对爬虫有不错的了解了 xff0c 也在之前已经写过不少爬虫了 xff0c 但我猜爬取的数据量都较小 xff0c 因此没有过多的关注爬虫的爬取效率 这里我想问问当我们要爬取的
  • c++多态和虚函数心得

    多态性 xff08 Polymorphism xff09 是指一个名字 xff0c 多种语义 xff1b 或界面相同 xff0c 多种实现 重载函数是多态性的一种简单形式 虚函数允许函数调用与函数体的联系在运行时才进行 xff0c 称为动态
  • IntelliJ IDEA 代码检查规范QAPlug

    转自 xff1a http blog csdn net jizi7618937 article details 51500725 Avoid Array Loops 数组之间的拷贝使用System arrayCopy更加高效 byte Re
  • linux系统中rpm与Yum软件仓库

    rpm的作用 xff1a 在没有rpm软件管理之前我们在安装 升级 卸载服务程序时要考虑到其他程序 库的依赖关系 xff0c 所以在进行安装 校验 卸载 升级等操作时的难度就非常之大 rpm机制则为就是为了解决这些问题而设计的 xff0c
  • Nokov使用说明(Windows系统)

    Nokov使用说明 第一步 镜头硬件调节1 连接镜头 xff0c 打开Seeker软件 xff08 以下简称软件 xff09 2 放置标定框3 调节镜头4 调焦1 xff09 调节后环 xff1a 光圈调到最大2 xff09 调节前环 xf
  • 计算机的存储器层次结构以及一二三级缓存的区别

    hibernate 一级缓存和二级缓存的区别 xff1a 主要的不同是它们的作用范围不同 一级缓存是session级别的 也就是只有在同一个session里缓存才起作用 xff0c 当这个session关闭后这个缓存就不存在了 而二级缓存是
  • Mac安装java反编译工具JD-GUI提示需要安装jdk1.8+解决方案

    一 下载 Java Decompiler JD Java Decompiler http java decompiler github io 二 当打开JD GUI软件时候 xff0c 会弹出以下错误 xff0c 见图示 xff1a 而自己
  • Docker命令详细说明

    Docker命令详细说明 docker help 查看docker帮助 使用方法 xff1a docker 命令选项 命令 参数 docker dameon help docker help v version config 61 dock
  • udev 规则文件介绍

    1 配置文件 udev的配置文件位于 etc udev 和 lib udev xff08 开头的是注释 xff09 udev 的主配置文件是 etc udev udev conf 它包含一套变量 xff0c 允许用户修改 udev 默认值
  • ATSAMV7Xult板卡调试Nuttx系统------NuttX模拟器SIM的的编译和调试

    NUTTX的模拟环境的编译和调试 xff1a 由于开发团队硬件资源紧张 xff0c 因此大家调试时可以使用模拟器来进行一些任务的开发和调试 参考 nuttx 7 17 configs sim readme txt介绍的操作方法 xff1a
  • C语言中,int、char、float、double各占多少字节

    https zhidao baidu com question 619738052995674092 html 只是数据类型不同而已 xff0c 在c语言中数据类型不同 xff0c 占的内存字节数不同 xff0c 所以表示数据大小不一样 i
  • 第一天做LeetCode 19.1.10

    为了备战蓝桥杯 xff0c 今天第一天做LeetCode xff0c 就做了一道题花了半个小时 xff0c 期间有各种错误 xff0c 深深的感受到自己连菜鸡都算不上 题目 xff1a 给定一个数组nums xff0c 与目标值target
  • 麻将通用胡牌算法详解(拆解法)

    1 背景 前几天刚好有项目需要胡牌算法 xff0c 查阅资料后 xff0c 大部分胡牌算法的博客都是只讲原理 xff0c 实现太过简单 xff0c 且没有给出测试用例 然后就有了下面的这个胡牌算法 xff0c 我将从算法原理和算法实现两部分
  • Java并发编程笔记之ThreadLocal内存泄漏探究

    转发 xff1a Java并发编程笔记之ThreadLocal内存泄漏探究 使用 ThreadLocal 不当可能会导致内存泄露 xff0c 是什么原因导致的内存泄漏呢 xff1f 我们首先看一个例子 xff0c 代码如下 xff1a Cr
  • 学长们的求职血泪史(C/C++/JAVA)

    2014届校招基本慢慢收尾 xff0c 现特将本人和小伙伴们的求职血泪史记录 xff0c 并且推荐一些书籍供学弟学妹们参考 xff0c 以壮我皇家理工之名 首先得感谢百度的师兄 xff0c 他教会了我很多东西 xff0c 致以很深的谢意 另
  • [海康威视]-超脑设备的 以图搜图 功能C#实现

    以图搜图意思就是海康超脑设备存储着人脸照片 xff0c 你用一张人脸照片去比对 xff0c 比对找个这个人的信息返回给你们 xff0c 识图拿代码
  • C++Builder PID控制一阶惯性系统

    ifndef Unit1H define Unit1H include lt Classes hpp gt include lt Controls hpp gt include lt StdCtrls hpp gt include lt F
  • kubernetes学习记录(14)——使用CustomResourceDefinitions(CRD)扩展Kubernetes API

    工作中即将开始写operator xff0c 先提前学习一下相关的知识 目前我们的kubernetes集群版本为1 15 0 xff0c 故参考文档为官方文档 Extend the Kubernetes API with CustomRes

随机推荐