算法导论之七快速排序

算法导论(一):快速排序与随机化快排 快速排序用到了分治思想,同样的还有归并排序。乍看起来快速排序和归并排序非常相似,都是将问题变小,先排序子串,最后合并。不同的是快速排序在划分子问题的时候经过多一步处理,将划分的两组数据划分为一大一小,这样在最后合并的时候就不必像归并排序那样再进行比较。但也正因为如此,划分的不定性使得快速排序的时间复杂度并不稳定。 阅读详情

1.        快速排序也采用了分治思想,下面是对子数组A[p..r]进行快速排序的三步分治过程:

分解:数组A[p..r]被划分为两个子数组(可能为空)A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每

一个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每一个元素。其中,计算

下标q也是划分过程的一部分。

解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。

合并:因为子数组都是通过原址排序的,因此不需要合并操作

 

伪代码实现快速排序:

QUICK-SORT(A,p,r)

         ifp < r

                   q= PARTITION(A,p,r)

                   QUICK-SORT(A,p,q-1)

                   QUICK-SORT(A,q+1,r)

PARTITION过程实现了对子数组A[p..r]的原址重排:

 PARTITION(A,p,r)

         x= A[r]

         i= p – 1

         forj = p to r – 1

                   ifA[j] <= x

                            i= i + 1

                            exchangeA[i] and A[j]

         exchangeA[i + 1] and A[r]

         returni + 1

分析:该过程选择A[r]作为主元,并围绕它来划分子数组A[p..r]。for循环中的每一区域均满足循环不变量,即对于任意的下标k,存在:

(1) 若p <= k <= i,则A[k] <=A[r]

(2) 若i + 1 <= k <= j – 1,则A[k] > A[r]

(3) 若k = r,则A[k] = x

在最后两行中,通过将主元与最左的大于x的元素进行交换,就可以将主元移到它在数组中的正确位置上,并返回主元的新下标。

2.        快速排序的性能

快速排序的运行时间依赖于划分是否平衡,如果是平衡的,则快速算法性能与归并排序一样,如果不平衡,则性能接近于插入排序。

3.        快速排序的程序代码:

#include<stdio.h>

 

//对R[i..j]做划分,并返回基准记录的位置

intPartition(int *R,int i,int j)

{

         int pivot=R[i];   //用区间的第一个记录作为基准

         while (i<j)          //从区间两端交替向中间扫描,直至i=j为止

         {

                   while (i<j &&R[j]>=pivot)         //pivot相当于在位置i上

                   {

                            j--;    //从右至左扫描,查找第一个关键字小于pivot的记录R[j]

                   }

                   if (i<j)

                   {

                            R[i++]=R[j];

                   }

                   while (i<j &&R[i]<=pivot)

                   {

                            i++;

                   }

                   if (i<j)

                   {

                            R[j--]=R[i];

                   }

         }

         R[i]=pivot;

         return i;

}

 

voidQuickSort(int *R,int low ,int high)

{

         int pivotpos;

         if (low<high)

         {

                   pivotpos=Partition(R,low,high);

                   QuickSort(R,low,pivotpos-1);

                   QuickSort(R,pivotpos+1,high);

         }

}

 

intmain()

{

         int S[10]={23,12,4,8,11,3,34,15,2,1};

         QuickSort(S,0,9);

 

         for (int i=0;i<10;i++)

         {

                   printf("%d  ",S[i]);

         }

         printf("\n");

}

4.        快速排序的随机化版本

/************************************************************************/

/*    

         快速排序算法:

         分解:数组A[p..r]被划分为两个子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]

                     中的每一个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每个数。

                     其中,计算下边q也是划分过程的一部分

         解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序

         合并:因为子数组都是原址排序的,所以不需要合并操作,数组A[p..r]已经有序

 

         QUICKSORT(A,p,r)

         if p<r

                   q=PARTITION(A,p,r)

                   QUICKSORT(A,p,q-1)

                   QUICKSORT(A,q+1,r)

 

         PARTITION过程实现了对子数组A[p..r]的原址重排

 

         PARTITION(A,p,r)

         x=A[r]

         i=p-1

         for j=p to r-1

                   if A[j]<=x

                            i=i+1

                            exchange A[i] withA[j]

         exchange A[i+1] with A[r]

         return i+1

 

         快速排序:最坏运行时间是O(n^2),期望的运行时间为θ(nlgn)

*/

/************************************************************************/

#include<stdio.h>

#include<math.h>

#include<stdlib.h>

#include<time.h>

 

intnum=10;

 

voidswap(int *a,int *b)

{

         int temp;

         temp=*a;

         *a=*b;

         *b=temp;

}

 

voidPrintArray(int arr[])

{

         for (int i=0;i<10;i++)

         {

                   printf("%d",arr[i]);

         }

}

 

intPartition(int *arr,int beg,int end)

{

         int j;

         int sentline1=arr[end];

         int i=beg-1;

 

         for (j=beg;j<=end-1;j++)

         {

                   if (arr[j]<=sentline1)

                   {

                            i++;

                            swap(&arr[i],&arr[j]);

                   }

         }

 

         swap(&arr[i+1],&arr[end]);

         printf("\n排序过程:\n");

         PrintArray(arr);

         return i+1;

}

 

intRadomPartition(int *arr,int beg,int end)

{

         int i=beg+rand()%(end-beg+1);

         swap(&arr[i],&arr[end]);

         return Partition(arr,beg,end);

}

 

voidRandomQuickSort(int *arr,int beg,int end)

{

         if (beg<end)

         {

                   intpivot=RadomPartition(arr,beg,end);

                   printf("\n随机选择 arr[%d](%d)",pivot,arr[pivot]);

                   RandomQuickSort(arr,beg,pivot-1);

                   printf("\n随机选择 arr[%d](%d)",pivot,arr[pivot]);

                   RandomQuickSort(arr,pivot+1,end);

         }

}

intmain()

{

         int i;

         int arr[10];

 

         srand(time(0));

         for (i=0;i<10;i++)

         {

                   arr[i]=rand()%100+1;

         }

 

         printf("初始数组:");

         PrintArray(arr);

 

         RandomQuickSort(arr,0,9);

 

         printf("\n最后结果:");

         PrintArray(arr);

 

         return 0;

}

《算法导论》第 7 章 - 快速排序 本文系统讲解了快速排序算法,包括其分治思想、划分操作和性能分析。快速排序通过选择基准元素将数组划分为两部分递归排序,平均时间复杂度为O(nlogn),但最坏情况下可能达到O(n^2)。文章提供了标准快速排序和随机化版本的C++实现,并讨论了优化策略:对于小数组可改用插入排序;对于重复元素可采用三路快速排序。快速排序因其优秀的平均性能和原地排序特性,成为实际应用中最常用的排序算法之一。文章还分析了算法的时间复杂度和空间复杂度,并给出了代码实现示例,帮助读者深入理解这一经典算法。 阅读详情

相关推荐

《算法导论》第7章 快速排序 (四种变形)

这一章的正文及思考题部分讲到了快速排序及其几种变形,包括:Hoare快排, 普通快排,随机快排,三数取中快排。 这些快排的区别主要是划分方法PARTITION算法的不同:如何选取主元,划分出的 两部分范围是什么。根据划分出的范围不同,各变形的QUICKSORT有微小的差别。 1. Hoare快排 Hoare划分是最初的版本,与《算法导论》中的划分版本相比,

西代零零发 4653

从设计循环不变量浅谈快速排序

写在前面   本人最近准备面试,在刷leetcode过程中遇到了类似于荷兰国旗的问题,于是特意回看了一下快速排序算法,也加深了对其的理解。作为一种feedback的方式,写一篇blog谈一谈对快排的认识。 目录 概述 基本算法 算法改进 例题 概述   快速排序是一种基于分治思想的排序算法。它之所以流行的原因有二:一是原地排序,且长度为N的数组排序所需时间与NlgN成正比;二是其内循环比多数排...

面包猎人 669

【算法导论】之快速排序深度分析

前言 最近学习了算法导论上的快速排序部分,有不少体会。 今天就来分享一下。在此欢迎大家批评指正文中的错误。 目录索引前言快速排序正文1.快速排序的优点2.快排的原理及实现3.快排的性能分析快排的几种优化方式1.主元的随机化选取2.三数取中3.减小递归的栈深度——小区间优化4.其他优化方法 快速排序 正文 1.快速排序的优点 说起快速排序,它的名字就显现出快排最大的优点————快。到底有多快呢?咱们用数据说话: 综合一般情况来说,快排确实有(亿点快)。特别是对较大数据量的排序。 快速排序的综合时间复杂度是O

程序员白菜 1760

快速排序算法_循环不变式,和快速排序算法的多种实现

在实际的日常工作,写出一个不正确的逻辑是一件很正常的事。虽然永无 bug 是一件不切实际的幻想,但是我们可以期望使用一些方法来尽可能地来靠近这个幻想。比如构造多种场景进行测试,比如使用循环不变式来验证算法正确性。这两者的侧重点和使用领域不尽相同,实际上,本文的重点——循环不变式更多的是理论上证明,附带帮助我们理解算法的正确性。如果算法本身存在错误,即使通过测试,那也只可能是测试场景构造缺失。在这篇...

weixin_39627144的博客 653

Reactor 响应式编程(第一篇:Reactor核心)

响应式:响应式编程: 全异步、消息、事件回调默认还是用当前线程,生成整个流、发布流、流操作.log();//只要不指定线程池,默认发布者用的线程就是订阅者的线程;

moments的博客 1572

算法面试八股文『 基础知识篇 』

个人整理的算法面试基础知识八股文,内容较详细。

SG_teresa's blog 4338

快速排序算法

经典算法 伪代码: quick-sort(A,p,r): if p<r: index=partition(A,p,r) quick_sort(A,p,index-1) quick_sort(A,index+1,r) partition(A,p,r): pv = A[r] i = p - 1 for j = p ...

xhdxhdxhd的博客 643

当GO.db安装失败时,生物信息学新手应该知道的5个底层逻辑

本文为生物信息学新手提供了解决GO.db安装失败的5个关键底层逻辑,包括网络连接与镜像源设置、版本兼容性检查、依赖关系管理、SQLite存储机制理解以及调试技巧。特别针对Bioconductor的GO.db包安装问题,详细介绍了如何通过切换国内镜像、管理版本冲突和解决依赖问题来成功安装,帮助用户高效克服常见安装障碍。

weixin_29062823的博客 407

算法导论 第七章 快速排序

7.1 快速排序描述 用分治策略进行排序: 分解:将数组A[p:r]划分为两个子数组A[p:q-1] 和 A[q+1:r],使得A[p:q-1]中的元素都小于等于A[q],且 A[q+1:r]中的元素都大于等于A[q],其中计算q也是划分过程的一部分。 解决:通过递归调用快速排序对两个子数组进行排序。 合并:进行原址排序,不需要合并 def QUICKSORT(A, p, r):

pokeyode的专栏 588

Argoverse轨迹预测实战:从数据加载到地图API应用全解析

本文详细解析了Argoverse数据集在轨迹预测中的应用,从数据加载到地图API的实战技巧全涵盖。通过具体代码示例展示如何高效处理轨迹数据、实现可视化及基础预测模型,帮助开发者快速掌握自动驾驶轨迹预测的核心技术。特别介绍了Argoverse地图API的深度应用和性能优化经验。

weixin_29182481的博客 241

Aurix TC387 Ethernet代码解析之二_移植

英飞凌官方仅提供了TC397的例程,故需通过TC397例程来移植到TC387新建工程里。TC397官方例程名称【Ethernet_1_KIT_TC397_TFT】,网络上可以免费获取到,此处不赘述。使用工具【

m0_69929716的博客 884

循环不变量求解数组问题

文章目录循环不变量原理快排移动 0去掉指定元素排序数组去重排序数组只保留最多2个重复的元素 循环不变量原理 第一次看到循环不变量是在算法导论的快排里。一般是针对数组问题求解,需要2个指针。 快排 快排最核心的思想是分区,也就是将给定数组分成2部分,左边比区间点小,右边比区间点大。使用循环不变量原理,以快排为例,指针 i, j 将数组分为3个部分。 其中 0 < i <= j ; i...

Odew 543

linux平台Modbus TCP测试

【代码】linux平台Modbus TCP测试。

无线互联&网络介绍 818

oracle快速排序法,算法导论(七)--快速排序

快速排序算法和合并排序算法一样,也是基于分治模式。对子数组A[p...r]快速排序的分治过程的三个步骤为:分解:把数组A[p...r]分为A[p...q-1]与A[q+1...r]两部分,其中A[p...q-1]中的每个元素都小于等于A[q]而A[q+1...r]中的每个元素都大于等于A[q];解决:通过递归调用快速排序,对子数组A[p...q-1]和A[q+1...r]进行排序;合并:因为两个子...

weixin_39975366的博客 271

IoT安全软件:Forescout二次开发_Forescout基础架构与原理

Forescout平台是一个集成了多种安全功能的综合解决方案,旨在帮助组织管理和保护其网络中的IoT设备。该平台通过自动发现、分类和监控网络中的设备,提供实时的安全可见性和控制。Forescout的核心优势在于其能够处理混合环境中的各种设备,包括传统IT设备、IoT设备和OT设备。Forescout平台由多个核心组件组成,每个组件负责特定的功能。了解这些组件的运作机制是进行二次开发的基础。假设我们需要定义一个策略,禁止所有厂商为XYZ的设备访问互联网。选择策略类型。

chenlz2007的博客 1965

Spring AI 实战:第五章、Spring AI本地模型部署之省钱小能手

白嫖的快乐你想象不到经过这番折腾,我们成功实现了零成本使用大模型完全本地运行保障隐私可视化访问Java生态无缝集成但可能有的小伙伴要吐槽,怎么换个底层模型这次就新建一个工程了呢?不能在以前的工程上开发吗?这样也太不优雅了吧~,我知道你很急,但先别急,等下一章节再来解决这个问题。为什么程序员特别喜欢Ollama?因为它就像一只温顺的羊驼——不花钱还能24小时产出代码!

liaokailin的专栏 922

算法导论学习笔记(七)- 快速排序

1快速排序概述      快速排序是一个使用分治思想的排序算法,具有如下优点:      1. 算法的期望运行时间为O(nlgn),且其中蕴含的常数因子较小,故而快速排序算法通常是实际应用中最好的选择。      2. 原址排序,排序过程中只需要有限个辅助空间。  ...

u010060373的博客 237

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

快速排序-《算法导论》学习笔记七

快排利用分治的思想,将问题规模切分为小的子规模问题,类似归并排序,归并是将两个待排序的子数组合并为一个有序的数组,而快排是将数组以某个数组值划分为两个子数组,一个数组的所有数比这个值小,一个数组的所有数比这个值大,然后再递归地对两个子数组再以某个数组值做切分和交换:#include <stdio.h> #include <string.h> #include <unistd.h> #include

lkness的博客 379

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

算法导论第七章:快速排序的艺术与科学

本文是《算法导论》精讲专栏第七章,通过**分治策略可视化**、**性能对比实验**和**工程优化技巧**,结合完整C语言实现,深入解析快速排序的精髓。包含基本实现、随机化优化、三向切分、尾递归消除等高级技术,提供10个以上完整代码实现。

SEU123WW的博客 1332

快速排序的四种python实现

快速排序算法,简称快排,是最实用的排序算法,没有之一,各大语言标准库的排序函数也基本都是基于快排实现的 本文用python语言介绍四种不同的快排实现 1. 一行代码实现的简洁版本 quick_sort = lambda array: array if len(array) array[0]]) 2. 网上常见的快排实现 def quick_sort(array, left

Razor87的专栏 10万+

算法导论实践——快速排序

算法导论实践——快速排序理论C# 实现FastSortUtilProgram 在学习算法导论之前,一直对快速排序有很大的畏惧感。还记得当时教我们数据结构的老师就硬给我们讲一堆算法,其中快速排序是真的叫我头疼。当时的感觉就是 我只看到了第一层,老师却在第五层 理论 分解:依据一个关键值(Pivot),把原数组分解成为两个子数组。其中一个子数组全部元素小于等于Pivot(后文称小数组)在Pivo...

不定期更新系统使用、编程小技巧,哔哩哔哩账号:https://space.bilibili.com/399455629,欢迎关注 326

算法导论 第7章 快速排序

一、概念 快速排序是基于分治模式的,选择一个数作为主元,经过一遍扫描,所有小于主元的数放在主元的左边,大于主元的数放在主元的右边,这样就划分成了两组数据。然后对两组数分别进行快排。 快排的运行时间与划分是否对称有关,关键是如何选择主元。 最坏情况下,时间复杂度是O(n^2),最好情况下,时间是O(nlgn) 二、程序 #include using namespace std;

幸福在路上 8220

《算法导论》伪代码C++实现--快速排序

《算法导论》第7章快速排序 /** * 快速排序 */ #include <bits/stdc++.h> using namespace std; int partition(int A[], int p, int r){ int i = p-1; for (int j = p; j <= r-1; ++j) { if (A[j] <...

edestiny1的博客 782

算法导论第七章-快速排序-Cpp代码实现

实现了算法导论第七章中的快速排序

YY的博客 860

《算法导论》第三版第7章 快速排序 练习&思考题 个人答案

7.1 快速排序的描述 7.1-1 解: 13, 19, 9, 5, 12, 8, 7, 4, 21, 2, 6, 11 9, 19, 13, 5, 12, 8, 7, 4, 21, 2, 6, 11 9, 5, 13, 19, 12, 8, 7, 4, 21, 2, 6, 11 9, 5, 8, 19, 12, 13, 7, 4, 21, 2, 6, 11 9, 5, 8, 7, 12, 13,...

张劲声的博客 1853

《算法导论》学习总结 — 6.第七章 快速排序

推荐先看看前言:http://www.cnblogs.com/tanky_woo/archive/2011/04/09/2010263.html其实这一篇我老早就写过了,只不过最近在总结《算法导论》,而第七章就是快速排序,我当初总结的快排也是根据算法导论来的,为了方便大家阅读,我在这里把曾经写过的重新再贴一遍。 前几天写过一个堆排序的文章(http://www.wutianqi.com/?p=...

weixin_30881367的博客 99
上一篇: 算法导论之五堆排序
下一篇: 算法导论之八计数排序
mengrennwpu
博客等级 码龄15年 262粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mengrennwpu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值