快速排序改进——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年提出. 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另 ...
随机推荐
- js--阻止冒泡,捕获,默认行为
防止冒泡和捕获 w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true· var el = window.document.getElementB ...
- 【SQL】glob 和 like 的区别
LIKE 和 GLOB 都可以用来匹配通配符指定模式的文本值.如果搜索表达式与模式表达式匹配,LIKE 运算符将返回真(true),也就是 1 区别: (1)使用的通配符不一样 like: 百分号( ...
- linux用户管理 用户和用户组信息
用户管理配置文件 用户信息文件 /etc/passwd 密码文件 /etc/shadow 用户配置文件 /etc/login.defs /etc/default/useradd 新用户信息文件 /e ...
- C#中使用FFMPEG切割、合并视频。
参考网址:https://blog.csdn.net/samwang_/article/details/70332924 使用前先确保电脑已经安装了FFMPEG,并且配置好环境变量.检测是否安装配置好 ...
- Python pycharm 引入需要使用的包
第一步 第二步 第三步
- ActiveMQ的发布者/订阅者模型示例
ActiveMQ的发布者/订阅者模型入门示例 (1)下载安装activemq,启动activeMQ. 详细步骤参考博客:http://www.cnblogs.com/DFX339/p/9050878. ...
- 根据访问ip的地区跳转到指定地址
<script type="text/javascript" src="http://ip.ws.126.net/ipquery"></scr ...
- Java多线程习题 ===重点 ,错题积累
多线程重点,错题分析 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: . 12: 13: 14: 15:
- S2 深入.NET和C#编程 笔试测试错题积累
---恢复内容开始--- <深入.NET平台和C#编程>内部测试题-笔试试卷错题积累 1: 1) 以下关于序列化和反序列化的描述错误的是( C). a) 序列化是将对象的状态存储到特定存储 ...
- 《Python》hashlib模块、configparser模块、logging模块
一.hashlib模块 Python的hashlib模块中提供了常见的摘要算法,如md5,sha1等等. 摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的字符串(通 ...