[排序算法] 如何解决快速排序特殊情况效率低的问题------三路划分

本文主要是介绍[排序算法] 如何解决快速排序特殊情况效率低的问题------三路划分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

        在[C/C++]排序算法 快速排序 (递归与非递归)一文中,对于快速排序的单趟排序一共讲了三种方法: hoare挖坑法双指针法 ,这三种方法实现的快速排序虽然在一般情况下效率很高,但是如果待排序数据存在大量重复数据,那这几种方法的效率就很低,而为了解决快速排序在这样特殊情况下效率低下的问题, 三路划分就可以完美解决

三路划分

思想:

        对于上述三种方法,其本质都是选定数组开头元素作特定值,让小的数据放左边,大的数据放右边。而三路划分顾名思义就是通过处理将数据分为三个部分 [小于特定值的部分   等于特定值的部分  大于特定值的部分] ,这样划分好后,只需要对小于特定值的部分和大于特定值的部分进行递归排序即可,中间的数据就不需要处理了,相比于上述三种方法效率提升很大,并且重复数据越多排序效率越快,当带排序数据全为重复数据时,时间复杂度甚至可以达到O(N)。

算法实现

首先我们定义一个cur指针指向begin的下一个元素,将begin开始所指元素定为关键值key

比较a[cur]与key的值,会出现三种情况

  1. 若a[cur]<key,交换a[begin]和a[cur], cur++, begin++
  2. 若a[cur]>key,交换a[end]和a[cur],end--
  3. 若a[cur]==key,cur++

重复比较操作,直到cur>end

[解释]:

为什么a[begin]和a[cur]交换后, cur要++, 而a[end]和a[cur]交换后,cur不和情况1一样++呢?

        因为a[end]和a[end]交换,目的是让大于key的值放到后面,而end所指元素我们不知道其与key的大小关系,所以下一次循环,还得判断其与key的关系才行,cur++会跳过这个元素。而begin初始所指元素就是关键值key, 当第一次找到比key小的数让两者交换,此时cur所指元素就是关键值,再仔细揣摩一下,只有小的数往左放的时候begin才会++,碰到大的数会把他往后放,放完还得比较当前cur所指的元素,碰到与key相同的元素不交换,cur往后走,这样我们会发现begin只会指向和key一样大的元素,所以交换完后,cur可以++。


单趟排序图解如下:

a[cur]<key,交换,cur++,begin++

a[cur]<key,交换,cur++,begin++

a[cur]==key, cur++

a[cur]==key, cur++

a[cur]>key,交换a[end]和a[cur],end--

a[cur]==key, cur++

a[cur]==key, cur++,此时cur>end,排序完成,将数据分为了三个部分

因为单趟排序排好后划分了三个部分,我们处理两边的部分需要返回两个值,所以就不单独封装三路划分的单趟排序了

代码如下:

void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}int GetMid(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[begin] > a[mid]){if (a[mid] > a[end])return mid;else if (a[begin] > a[end])return end;elsereturn begin;}else{if (a[begin] > a[end])return begin;else if (a[mid] > a[end])return end;elsereturn mid;}
}void QuickSort(int* a, int begin, int end)
{if (begin >= end)return;int mid = GetMid(a, begin, end);swap(&a[begin], &a[mid]);//由于begin和end要改变,提前保存,便于递归使用int left = begin;int right = end;int cur = begin + 1;int key = a[begin];while (cur <= end){if (a[cur] < key){swap(&a[cur], &a[begin]);begin++;cur++;}else if (a[cur] > key){swap(&a[cur], &a[end]);end--;}else{cur++;}}QuickSort(a, left, begin - 1);QuickSort(a, end + 1, right);
}

这篇关于[排序算法] 如何解决快速排序特殊情况效率低的问题------三路划分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572098

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短