快速排序改进——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年提出. 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另 ...
随机推荐
- 逆袭之旅DAY10.东软实训.
- django_rq无法监听两个队列问题
django_rq是为django集成redis队列,这个用的少,一般会选择celery,没办法项目中用到了.用起来很简单,配置可以参考官方文档:https://pypi.org/project/dj ...
- Java单例模式《二》懒汉式
package com.study.mode; /** * 单例模式: 懒汉式,需要的时候创建. * @ClassName: SingleBean2 * @author BlueLake * @dat ...
- Cracking The Coding Interview 9.6
//原文: // // Given a matrix in which each row and each column is sorted, write a method to find an el ...
- C++基础知识:构造与析构
1.构造函数的定义: C++中的类可以定义与类名相同的特殊成员函数这种与类名相同的成员函数叫做构造函数构造函数在定义时可以有参数,但是没有任何返回类型的声明 2.构造函数的调用: 一般情况下C++编译 ...
- DevExpress WinForms使用教程:新的CheckEdit样式
[DevExpress WinForms v18.2下载] 在最开始CheckEdit控件有16种样式, 使用CheckStyle属性,开发人员可以选择其中一种样式.随着时间推移,与其他Windows ...
- codeforce150A(简单的求质数问题)
A. Win or Freeze time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- Git客户端的安装与配置入门
GitLab与Git客户端的安装与配置入门,每次配置完一段时间,就忘记配置过程了,为了自己和同学们以后有所参照,特记录了本次下载和配置,其实Git就是一个版本控制系统,类似于SVN,CVS等 下载:W ...
- ios表单验证帮助类
// // ValidateHelper.h // #import <Foundation/Foundation.h> @interface ValidateHelper : NSObje ...
- SpringMVC实现从磁盘中下载文件
除了文件的上传我们还需要从磁盘下载 实现文件的下载只要编写一个控制器,完成读写操作和响应头和数据类型的设置就可以了 下面演示的是从G盘imgs文件夹中下载文件 具体代码如下 package com.c ...