zoukankan      html  css  js  c++  java
  • 排序算法—希尔排序

    1.排序问题

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

      例如:

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

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

    2.解决方法A

      从第一项逐步读到最后一项。每读一项,便把它与之前读过的数字全部进行比较,并把它放在大小合适的位置(大于等于前一个,小于等于后一个)。

      这种解法固然可以解决问题,但是效率不够高。

      实现代码大概是这样子的:

    3.解决方法B:希尔排序(ShellSort)

      为了高效地解决这个问题,这里引入希尔排序。

      与方法A思路类似,但此算法不是逐个读下去,而是跳着读。

      例如4个4个跳着读:

      即第一次排序第1,5,9,13项;第二次排序第2,6,10,14项;第三次排序第3,7,11,15项;第四次排序第4,8,12,16项;然后一个一个地排序。由于数组经过4个4个地排,变成了部分有序数组,此时再逐一排序,则会排得比方法A快(因为方法A是完全无序的,每次排都有可能要从头比较到尾)。

      那么,应该跳多少个来读下去呢?目前还是个数学难题,大家发现3X+1相对较快。以下的实现也是用3X+1。

      解决一开始提出的排序问题的代码实现:

    .h: 
    
    UCLASS()
    class ALGORITHM_API AShellSort : public AActor
    {
        GENERATED_BODY()
        
    public:    
        // Sets default values for this actor's properties
        AShellSort();
    
        // Called every frame
        virtual void Tick(float DeltaTime) override;
        //生成数组
        void InitArray(int N);
        //更换数组里两个数字
        void ExChange(int i, int j);
        //比较数组里两个数字的大小
        bool Less(int i, int j);
        //希尔排序(ShellSort)
        void ShellSort();
    
    protected:
        // Called when the game starts or when spawned
        virtual void BeginPlay() override;
    
    public:    
        
        TArray<int> MyIntArray;
    };
    
    .cpp:
    
    AShellSort::AShellSort()
    {
         // 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 AShellSort::BeginPlay()
    {
        Super::BeginPlay();
        //测试
        //生成数组
        InitArray(100000);
        //排序前
        for (int i = 0; i < MyIntArray.Num(); i++)
        {
            UKismetSystemLibrary::PrintString(this, "Before: " + FString::FromInt(i)+" : "+FString::FromInt(MyIntArray[i]));
        }
        ShellSort();
        //排序后
        for (int i = 0; i < MyIntArray.Num(); i++)
        {
            UKismetSystemLibrary::PrintString(this, "After: " + FString::FromInt(i) + " : " + FString::FromInt(MyIntArray[i]));
        }
    }
    
    // Called every frame
    void AShellSort::Tick(float DeltaTime)
    {
        Super::Tick(DeltaTime);
    
    }
    
    //生成随机数组
    void AShellSort::InitArray(int N)
    {
        FRandomStream Stream;
        Stream.GenerateNewSeed();
        for (int i = 0; i < N; i++)
        {
            MyIntArray.Add(Stream.RandRange(0, 100));
        }
    }
    
    void AShellSort::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;
    }
    
    bool AShellSort::Less(int i, int j) 
    {
        //序号i,j应该在数组范围内
        if (i > MyIntArray.Num() - 1 || j > MyIntArray.Num() - 1) return false;
        //比较大小
        return MyIntArray[i] < MyIntArray[j];
    }
    
    void AShellSort::ShellSort()
    {
        int N(MyIntArray.Num());
        int h(1);
        //用3x+1的间距分割数组,先找出最大的h
        while (h < N / 3) h = 3 * h + 1;
        //以h为间隔排序数组(h-sort)
        while (h >= 1)
        {
            for (int i = h; i < N; i++)
            {
                for (int j = i; j >= h && Less(j, j - h); j -= h)
                {
                    ExChange(j, j - h);
                }
            }
            //寻找下一个h,直到h=1为止
            h = h / 3;
        }
    }
  • 相关阅读:
    lampp、xampp安装文档
    tomcat下配置https方式
    1.6:怎么学习Linux
    1.5:linux的应用领域
    1.3:linux的优点和缺点
    1.4:Linux发行版本详解
    1.2:liunx和unix的区别
    1.1:Linux系统简介
    mysql中获取表名&字段名的查询语句
    kettle组件-输出
  • 原文地址:https://www.cnblogs.com/mcomco/p/10114793.html
Copyright © 2011-2022 走看看