快速排序改进——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年提出. 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另 ...
随机推荐
- jsp 中文乱码
解决jsp中文乱码问题的几个步骤 1 jsp页面设置 <%@ page language="java" contentType="text/html; ...
- pyhton-函数初级
f = open("司马光砸缸", mode="r+", encoding="utf-8") f.seek(12) f.truncate() ...
- Unity3D在C#编程中的一些命名空间的引用及说明
System包含用于定义常用值和引用数据类型.事件和事件处理程序.接口.属性和处理异常的基础类和基类.其他类提供支持下列操作的服务:数据类型转换,方法参数操作,数学计算,远程和本地程序调用,应用程序环 ...
- Python Select模型(程序流程)(转)
缘由 之前写socket的CS模型代码,都是利用最原始的多线程方式.服务端是主线程,接到客户端的连接请求就从线程池中获取一个线程去处理整个socket连接的所有操作,虽然在连接数较短的情况下没有什么影 ...
- Linux学习: LCD驱动
一.LCD驱动框架: 1.分配一个fb_info结构体:s3c_lcd = framebuffer_alloc(0,NULL); 2.设置fb_info(s3c_lcd): ID.固定参数.可变参数. ...
- django的FBV和CBV的装饰器例子
备忘 def auth(func): def inner(request,*args,**kwargs): u = request.COOKIES.get('username111') if not ...
- Unity3d代码及效率优化总结
1.PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU. 2.如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unli ...
- ::selection 选择器
使被选中的文本成为红色:::selection { color:#ff0000; } ::-moz-selection { color:#ff0000; }
- 6.Python爬虫入门六之Cookie的使用
大家好哈,上一节我们研究了一下爬虫的异常处理问题,那么接下来我们一起来看一下Cookie的使用. 为什么要使用Cookie呢? Cookie,指某些网站为了辨别用户身份.进行session跟踪而储存在 ...
- 2019.3.5 L261 Are All Our Organs Vital?
Medicine has not always shown a lot of respect for the human body. Just think about the ghoulish dis ...