快速排序改进——3区快速排序(3-way quicksort)
1.快速排序缺陷
快速排序面对重复的元素时的处理方法是,把它放在了左部分数组或右部分数组,下次进行分区时,还需检测它。如果需要排序的数组含有大量重复元素,则这个问题会造成性能浪费。
解决方法:新增一个相同区域,并把重复元素放进去,下次进行分区时,不对相同区域进行分区。
2. 3区快速排序(3-way quicksort)
从例子入手:

现有数组A[]如上图。
令int lt=0; int i =1; int gt=5;
首先从A[0](53)开始
A[lt]与A[i]进行对比,结果:A[0]<A[1], 交换A[i]与A[gt], gt减一:

A[lt]与A[i]进行对比,结果:A[0]>A[1], 交换A[i]与A[lt], lt加一,i加一:

A[lt]与A[i]进行对比,结果:A[1]>A[2],交换A[i]与A[lt], lt加一,i加一:

A[lt]与A[i]进行对比,结果:A[2]=A[3],i加一:

A[lt]与A[i]进行对比,结果:A[1]>A[2],交换A[i]与A[lt], lt加一,i加一:

i>gt,第一次排序结束。
此时,整个数组分为3个区:
第一个区里的所有数字都比53小,它含有a[0]~a[2];
第二个区里的所有数字都等于53,它含有a[3]~a[4];
第三个的所有数字都比53大,它含有a[5];
我们还需要对第一个区和第三个区进行3区快速排序(因为这两个区里的数字可能还是乱的,虽然在本例中顺序是对的)
从第一个区的第一个数字20开始:
令int lt=0; int i =1; int gt=2;

A[lt]与A[i]进行对比,结果:A[2]=A[3],i加一:

A[lt]与A[i]进行对比,结果:A[0]<A[2], 交换A[i]与A[gt], gt减一:(这里i=gt,所以等于没交换)

i>gt,第二次排序结束。
此时,整个区分为3个区:
第一个区里的所有数字都比20小,它没有元素;
第二个区里的所有数字都等于20,它含有a[0]~a[1];
第三个的所有数字都比20大,它含有a[2];
对第一个区和第三个区进行3区快速排序,但第一个区没元素,不用排;第三个区只有一个元素,不用排。

对下一个区进行3区快速排序,但此区只有A[5]一个元素,不用排;
没有下一个区了,排序结束。
总结一下:
对于一个数组A[],令lt=0;i=1,gt为数组的最后一个元素的序号(index)。
1.从A[lt]开始,如果A[lt]>A[i],交换lt项元素和i项元素,lt++,i++;如果A[lt]=A[i], i++;如果A[lt]<A[i],交换gt项元素和i项元素,gt--。
2.当i>gt时,数组已经分好3个区域了。
3.对大于A[lt]的元素区域和小于A[lt]的元素区域分别进行3区快速排序,直到分区数组只有一个元素为止。
3.实现代码
.h: UCLASS()
class ALGORITHM_API AThreeWayQuicksort : public AActor
{
GENERATED_BODY() public:
// Sets default values for this actor's properties
AThreeWayQuicksort();
// Called every frame
virtual void Tick(float DeltaTime) override; //生成数组
void InitArray(int N);
//更换数组里两个数字
void ExChange(int i, int j);
//开始排序
void Sort();
void Sort(int lo, int hi);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; public: private:
TArray<int> MyIntArray;
}; .cpp: // Sets default values
AThreeWayQuicksort::AThreeWayQuicksort()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
} // Called when the game starts or when spawned
void AThreeWayQuicksort::BeginPlay()
{
Super::BeginPlay();
//测试
//生成数组
InitArray();
UKismetSystemLibrary::PrintString(this, "Before Sort: ");
for (int i = ; i < MyIntArray.Num(); i++)
{
UKismetSystemLibrary::PrintString(this, FString::FromInt(i) + " : " + FString::FromInt(MyIntArray[i]));
}
//开始排序
Sort();
UKismetSystemLibrary::PrintString(this, "After Sort: ");
for (int i = ; i < MyIntArray.Num(); i++)
{
UKismetSystemLibrary::PrintString(this, FString::FromInt(i) + " : " + FString::FromInt(MyIntArray[i]));
}
} // Called every frame
void AThreeWayQuicksort::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
} void AThreeWayQuicksort::InitArray(int N)
{
FRandomStream Stream;
Stream.GenerateNewSeed();
for (int i = ; i < N; i++)
{
MyIntArray.Add(Stream.RandRange(, ));
}
} void AThreeWayQuicksort::ExChange(int i, int j)
{
//序号i,j应该在数组范围内
if (i > MyIntArray.Num() - || j > MyIntArray.Num() - ) return;
//互换
int Tempint = MyIntArray[i];
MyIntArray[i] = MyIntArray[j];
MyIntArray[j] = Tempint;
} void AThreeWayQuicksort::Sort()
{
Sort(, MyIntArray.Num() - );
} void AThreeWayQuicksort::Sort(int lo, int hi)
{
if (hi <= lo) return;
//left是小于V和等于V的分界线
int Left(lo);
//Right是大于V和等于V的分界线
int Right(hi);
int V(MyIntArray[lo]);
//i是等于V和未排序元素的分界线
int i(lo);
while (i <= Right)
{
//如果小于V,放在Left的左边(小于V的元素区间)
if (MyIntArray[i] < V) ExChange(Left++, i++);
//如果大于V,放在Right的右边(大于V的元素区间)
else if (MyIntArray[i] > V) ExChange(i, Right--);
//如果等于V,i++,相当于放在Left和i之间(等于V的元素区间)
else i++;
}
//然后这两部分数组作为新的部分数组继续分下去,直到hi <= lo
Sort(lo, Left - );
Sort(Right + , hi);
}
快速排序改进——3区快速排序(3-way quicksort)的更多相关文章
- 分治思想的应用:C++实现快速排序和随机化的快速排序
分治思想的应用:C++实现快速排序和随机化的快速排序 原创 2014年09月08日 14:04:49 标签: 快速排序 / 随机化快速排序 / 排序算法 / 数据结构 947 1. 快速排序时冒泡排序 ...
- 快速排序 Java实现的快速排序
快速排序 Java实现的快速排序: package xc; import java.util.Arrays; import java.util.Random; /** * * @author dax ...
- c++之快速排序改进(随机值)
数量少(5~25),插入排序很高效 一个影响快排效率的因素就是: 基准值的选择 本文将演示一种随之法的快排 改进前 void quick_sort5(int arr[], int low, int h ...
- 排序算法练习--JAVA(插入、直接选择、冒泡、快速排序、非递归快速排序)
排序算法是数据结构中的经典算法知识点,也是笔试面试中经常考察的问题,平常学的不扎实笔试时候容易出洋相,回来恶补,尤其是碰到递归很可能被问到怎么用非递归实现... package sort; impor ...
- java算法面试题:设计一个快速排序。双路快速排序,简单易于理解。
package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util.Compar ...
- 从一组数找第K大元素
最近做面试题,经常与到一个问题,如何高效的从一组数中找到第K大的元素. 其实我们最容易想到的肯定是蛮力法. 1. 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*l ...
- 快速排序QuickSort
前几天实现了直接插入排序.冒泡排序和直接选择排序这三个基础排序.今天看了一下冒泡排序的改进算法,快速排序.单独记录一下,后面还有归并和基数排序等 快速排序 1.选择一个支点默认为数组第一个元素及arr ...
- 快速排序(QuickSort)
1.算法思想 快速排序是一种划分交换排序.它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod). (1) 分治法的基本思想 分治法的基本思想是:将原 ...
- Html5 快速排序演示
快速排序(Quicksort)是对冒泡排序的一种改进.快速排序由C. A. R. Hoare在1962年提出. 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另 ...
随机推荐
- 4.3 if-else语句使用
Q:对输入的成绩进行登记划分. #include<iostream> #include<cstdio> using namespace std; int main() { in ...
- daay04流程控制之for循环
for循环主要用于循环取值 student=['egon','虎老师','lxxdsb','alexdsb','wupeiqisb'] # i=0 # while i < len(student ...
- JavaScript -基础- 函数与对象
一.JavaScript三对象 1.分类方式一 1)ECMAScript JavaScript的ECMA规范 JS本身的对象 2)Dom 操作HTML相关 3)BOM游览器对象 游览器窗口对象,全局的 ...
- MySQl 主从配置实战
目前后台数据库使用了一个实例做数据统计分析,随着数据井喷,单个实例无法做数据分析.故开始了读写分离. 1.主配置 [client] port = 3306 socket = /tmp/mysql-33 ...
- 三:使用docker-machine安装虚拟机上的docker
1.docker安装之后自带docker-machine:(需要win10专业版或mac) 2.如何远程管理一个docker-machine?(以下是Mac环境) 关闭本地的docker应用.运行do ...
- 通过eclipse创建项目
基于eclipse的Java文件:项目(project)<类(class)<方法(method),即方法method必须基于class, class必须基于project. 项目是程序的源 ...
- Centos防火墙设置与端口开放的方法
Centos升级到7之后,内置的防火墙已经从iptables变成了firewalld.所以,端口的开启还是要从两种情况来说明的,即iptables和firewalld.更多关于CentOs防火墙的最新 ...
- 重载方法写delete请求
#encoding=utf-8#__author__="Lanyangyang" import unittestimport requestsimport json # This ...
- .NET界面控件DevExpress全新发布v18.2.6|附下载
DevExpress Universal Subscription(又名DevExpress宇宙版或DXperience Universal Suite)是全球使用广泛的.NET用户界面控件套包,De ...
- DevExpress v18.1新版亮点——DevExtreme篇(一)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme JavaScript Controls v18.1 的新功能 ...