1、归并,非递归实现
(1)段长度倍增,1,2,3,4,8,...,n
当要合并的单段长<n时,继续合并,直到单段长度>=n就跳出循环。
(2)以两段的长度作为每次偏移的长度
每次合并是两个单段一组进行合并,因此要不断地偏移两个单段的长度。
/*
5
3 5 2 8 7
2 3 5 7 8
*/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; i++)
cin >> nums[i];
for (int s = 1; s < n; s *= 2) //单段长度,倍增
{
for (int i = 0; i < n; i += 2 * s) //每段的偏移,2倍段长度偏移
{
//要归并的区间
int begin = i; //
int mid = min(i + s, n); // 必须要取最小值,避免溢出
int end = min(i + 2 * s, n); // 必须要取最小值,避免溢出
if (mid >= n) continue; //只有一段时,避免再进行无用的归并,会拷贝内容。
//归并
int p = begin;
int q = mid;
vector<int> temp; // 临时存放,本段排序结果
while (p < mid && q < end)
{
if (nums[p] <= nums[q])
temp.push_back(nums[p++]);
else
temp.push_back(nums[q++]);
}
while (p < mid)
temp.push_back(nums[p++]);
while (q < end)
temp.push_back(nums[q++]);
// 回拷贝
for (int k = begin; k < end; k++)
{
nums[k] = temp[k - begin];
}
}
}
for (int i = 0; i < n; i++)
cout << nums[i] << ' ';
return 0;
}