将两个有序表合并成一个有序表,称为二路归并。
.h:
UCLASS()
class ALGORITHM_API AMergesort : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMergesort();
// Called every frame
virtual void Tick(float DeltaTime) override;
//生成数组
void InitArray(int N);
//检测这部分的数组是否有序
void IsSorted(int MinIndex, int MaxIndex);
//归并排序(MergeSort),输入辅助数组及此部分数组的最小id、中间Id、最大id
void Merge(TArray<int> AuArray, int lo, int mid, int hi);
//开始排序
void Sort();
void Sort(TArray<int> AuArray, int lo, int hi);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
//目标数组
TArray<int> MyIntArray;
};
.cpp:
// Sets default values
AMergesort::AMergesort()
{
// 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 AMergesort::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 AMergesort::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
//生成随机数组
void AMergesort::InitArray(int N)
{
FRandomStream Stream;
Stream.GenerateNewSeed();
for (int i = 0; i < N; i++)
{
MyIntArray.Add(Stream.RandRange(0, 100));
}
}
void AMergesort::IsSorted(int MinIndex, int MaxIndex)
{
//这部分数组应该在整个数组之内
if (MaxIndex > MyIntArray.Num() || MinIndex > MyIntArray.Num()) return;
//检测数组
for (int i = MinIndex; i < MaxIndex - 2; i++)
{
//如果有序,前一项应该小于等于后一项
if (MyIntArray[i] > MyIntArray[i + 1])
{
UKismetSystemLibrary::PrintString(this, " Error: UnOrder");
return;
}
}
}
//合并部分数组
void AMergesort::Merge(TArray<int> AuArray, int lo, int mid, int hi)
{
//先检测前半段和后半段是否都是有序的
IsSorted(lo, mid);
IsSorted(mid + 1, hi);
//把这一部分数组拷贝给辅助数组
for (int k = lo; k <= hi; k++)
{
AuArray[k] = MyIntArray[k];
}
//前半段和后半段的起始序号
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++)
{
//如果前半段已经没有了,则把后半段直接加上去
//PS:MyIntArray[k] = AuArray[j++]等效于MyIntArray[k] = AuArray[j]; j++;
if (i > mid) MyIntArray[k] = AuArray[j++];
//如果后半段已经没有了,则把前半段直接加上去
else if (j > hi) MyIntArray[k] = AuArray[i++];
//如果i项元素比j项元素大,则取j项元素
else if (AuArray[i] > AuArray[j]) MyIntArray[k] = AuArray[j++];
//否则取i项元素
else MyIntArray[k] = AuArray[i++];
}
//检查数组排序有没问题
IsSorted(lo, hi);
}
//开始排序
void AMergesort::Sort()
{
//创造一个与目标数组同等大小的辅助数组
TArray<int> AuArray;
AuArray.Init(0, MyIntArray.Num());
Sort(AuArray, 0, MyIntArray.Num() - 1);
}
void AMergesort::Sort(TArray<int> AuArray, int lo, int hi)
{
if (hi <= lo) return;
//处于中间的元素的ID
int mid = lo + (hi - lo) / 2;
//把前半段不停地分割成两部分,然后从最小的部分开始合并,最后得到有序的前半部分
Sort(AuArray, lo, mid);
//把后半段不停地分割成两部分,然后从最小的部分开始合并,最后得到有序的后半部分
Sort(AuArray, mid + 1, hi);
//最后把前半部分和后半部分合并,得到有序的数组,排序完成
Merge(AuArray, lo, mid, hi);
}