归并排序算法(递归和非递归)
从left到m下标是从小到大排序,从m+1到right下标是从小到大排序。
我们要把这些数据并轨到目标块中,然后我们再把目标块中的数据拷贝到src圆里面
非递归实现
右图是我们的圆src,分为2个部分,左半部分从小到大,右半部分从小到大,left是左半部分的首地址,m是中间划分的地址,right是右半部分的尾地址。k指向左半部分的首地址,也是目的的首地址。
谁小就把谁往目的里放。这个程序是把圆的数据导入到目的。并没有把目的往圆里拷贝。
void Merge(int *dist,int *src, int left, int m, int right)
{
int i = left, j = m + 1;
int k = left;
while (i <= m && j <= right)
{
dist[k++] = src[i] < src[j] ? src[i++] : src[j++];
}
while (i <= m)
{
dist[k++] = src[i++];
}
while (j <= right)
{
dist[k++] = src[j++];
}
}
拷贝函数
void Copy(int* dist, int* src, int left, int right)
{
for (int i = left; i <= right; ++i)
{
dist[i] = src[i];
}
}
并轨排序(递归)
void MergePass(int* br, int* ar, int left, int right)//划分
{
if (left < right)
{
int mid = (right - left) / 2 + left;
MergePass(br, ar, left, mid);
MergePass(br, ar, mid + 1, right);
Merge(br, ar, left, mid, right);
Copy(ar, br, left, right);
}
}
void MergeSort(int* ar, int n)
{
if (ar == nullptr || n < 1) return;
int* br = new int[n];
MergePass(br, ar, 0, n - 1);
delete[] br;
}
int main()
{
int ar[] = { 14,56,34,100,23,78,93,12,45,67,88 };
int n = sizeof(ar) / sizeof(ar[0]);
MergeSort(ar, n);
for (auto & x : ar)
{
cout << x << " ";
}
cout << endl;
return 0;
}
并轨排序(非递归)
首先ar向br并轨
然后br向ar并轨
然后继续while循环
s就是每个区域有几个值
for ( ; i+2*s <= n; i = i + 2 * s)
i = i + 2 * s 两个区域加上起始位置的值,就是下一个区域的起始位置
图解
并轨排序非递归的程序代码
void MergePass(int* dist, int* src,int n,int s)//划分
{ // i+2*s-1 <= n-1
int i = 0;
for ( ; i+2*s <= n; i = i + 2 * s)
{
Merge(dist, src, i, i + s - 1, i + 2 * s - 1);//0,1,3
}
if (n-1 > i+s-1)//最后一个元素的下标大于前一个下标,说明第二部分有数据,要并轨
//并轨到最后的部分,有缺失的数据,如,两个值和一个值并轨
{
Merge(dist, src, i, i + s - 1, n - 1);//n-1:最后一个元素的下标
}
else//直接拷贝进去
{
for (int j = i; j < n; ++j)
{
dist[j] = src[j];
}
}
}
void MergeSort(int* ar, int n)//并轨排序
{
if (ar == nullptr || n < 1) return;
int* br = new int[n];
int s = 1;
while (s < n)
{
MergePass(br, ar, n, s); //s的值//1//4//16
s += s;
MergePass(ar, br, n, s); //s的值//2//8
s += s;
}
delete[]br;
}