• 排序算法—快速排序


    1.排序问题

      现有一个含有N个数字的数组S,如何通过程序把这个数组变成有序的数组?

      例如:

      排序前:S:5,3,7,5,9,4,1,100,50

      排序后:S:1,3,4,5,5,7,9,50,100

    2.快速排序(Quicksort)

      简单介绍:  

      快速排序内含一道重要的工序:分区(Partition)。这里将先介绍分区,然后介绍排序方法。

    分区:

      

      对于一个数组,将它的第一个元素设为V,令i=2,j为数组的最后一个元素的序号(index)。

      1.先从i开始比较,如果i项元素比V小,则i++;否则停止比较,此时的i项元素大于等于V。

      2.然后从j开始比较,如果j项元素比V大,则j--;否则停止比较,此时的i项元素小于等于V。

      3.如果i<j,说明i项元素和j项元素之间还有元素,将i项元素和j项元素互换,然后i++,j--,然后重复1,2,3步骤,直到i和j重合(即i=j)。

      4.将J项元素和V互换。这样就得到了一个分好区的数组:V的左端的元素都小于等于V;V的右端都大于等于V。

    排序:

      1.将整个数组进行分区。

      2.对分区得到的两个部分数组分别进行分区,不停的分区下去,直到分区数组只有一个元素为止。

      3.排序完成。

    3.快速排序的优缺点

    优点:

    不需要额外空间(归并排序需要一个额外数组),速度比归并排序快。

    缺点:

    1.如果数组是递增的有序数组,对它用快速排序需要N2/2次操作。

    2.No Stable:如果数组已经按一种排序方式排成有序了,然后再按另一种排序方式用快速排序对此数组排序,则会打乱第一种排序。(例如手机通讯录先按地区排了一次序,再按名字排一次序。)PS:归并排序是Stable的。

    4.快速排序具体代码实现:

    .h:
    
    UCLASS()
    class ALGORITHM_API AQuicksort : public AActor
    {
        GENERATED_BODY()
        
    public:    
        // Sets default values for this actor's properties
        AQuicksort();
        // Called every frame
        virtual void Tick(float DeltaTime) override;
    
        //生成数组
        void InitArray(int N);
        //把此部分数组分为两半,中间分界线为v,左半部分的数字都比v小,右半部分的数字都比v大
        int Partition(int lo, int hi);
        //更换数组里两个数字
        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
    AQuicksort::AQuicksort()
    {
         // 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 AQuicksort::BeginPlay()
    {
        Super::BeginPlay();
        //测试
        //生成数组
        InitArray(10000);
        UKismetSystemLibrary::PrintString(this, "Before Sort: ");
        for (int i = 0; i < MyIntArray.Num(); i++)
        {
            UKismetSystemLibrary::PrintString(this, FString::FromInt(i) + " : " + FString::FromInt(MyIntArray[i]));
        }
        //开始排序
        Sort();
        UKismetSystemLibrary::PrintString(this, "After Sort: ");
        for (int i = 0; i < MyIntArray.Num(); i++)
        {
            UKismetSystemLibrary::PrintString(this, FString::FromInt(i) + " : " + FString::FromInt(MyIntArray[i]));
        }
        
    }
    
    // Called every frame
    void AQuicksort::Tick(float DeltaTime)
    {
        Super::Tick(DeltaTime);
    
    }
    
    void AQuicksort::InitArray(int N)
    {
        FRandomStream Stream;
        Stream.GenerateNewSeed();
        for (int i = 0; i < N; i++)
        {
            MyIntArray.Add(Stream.RandRange(0, 100));
        }
    }
    
    int AQuicksort::Partition(int lo, int hi)
    {
        int i(lo);
        //因为后面会--j,而我们需要从hi项开始比较,所以这里j=hi+1
        int j(hi + 1);
        //只要中途不break,循环一直进行下去
        while (true)
        {
            //lo项作为比较用的元素,从lo+1开始比较,直到找到大于等于lo项的元素,才停止(除非lo项是此部分数组中最大的,此时i=hi)
            //停止时,i项元素比lo项大
            //注意:MyIntArray[++i] < MyIntArray[lo]中,先进行++i,再进行比较
            while (MyIntArray[++i] < MyIntArray[lo])
            {
                if (i == hi) break;
            }
            //从hi项开始比较,直到找到小于等于lo项的元素,才停止(除非lo项是此部分数组中最小的,此时i=lo)
            //注意:MyIntArray[lo]<MyIntArray[--j]中,先进行--j,再进行比较
            while (MyIntArray[lo]<MyIntArray[--j])
            {
                if (j == lo) break;
            }
    
            //如果i >= j,说明i,j重合了,不需要继续循环。此时,i项左边的元素都比lo项小;右边的元素都比lo项大
            if (i >= j) break;
            //如果i和j之间还有元素,说明还没比较完,继续比较
            ExChange(i, j);
        }
        //lo项是分界线元素,把它放到分界线处
        ExChange(lo, j);
        //返回分界线元素的Index
        return j;
    }
    
    void AQuicksort::ExChange(int i, int j)
    {
        //序号i,j应该在数组范围内
        if (i > MyIntArray.Num() - 1 || j > MyIntArray.Num() - 1) return;
        //互换
        int Tempint = MyIntArray[i];
        MyIntArray[i] = MyIntArray[j];
        MyIntArray[j] = Tempint;
    }
    
    void AQuicksort::Sort()
    {
        Sort(0, MyIntArray.Num() - 1);
    }
    
    void AQuicksort::Sort(int lo, int hi)
    {
        if (hi <= lo) return;
        //把此部分数组分为两部分
        int j = Partition(lo, hi);
        //然后这两部分数组作为新的部分数组继续分下去,直到hi <= lo
        Sort(lo, j - 1);
        Sort(j + 1, hi);
    }
  • 相关阅读:
    HTTP状态码
    Hibernate的配置与简单使用
    Java基础学习总结 -- 多线程的实现
    MySQL学习笔记 -- 数据表的基本操作
    Java基础学习 -- I/O系统、流
    理解文件的编码
    Java基础学习 -- 异常
    Java基础学习 -- GUI之 事件处理基础
    Java基础学习总结 -- 图形用户界面GUI
    Java基础学习 -- 接口
  • 原文地址:https://www.cnblogs.com/mcomco/p/10137601.html
Copyright © 2020-2023  润新知