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; } }