归并排序
- 基本思想:
取两个输入数组A和B,一个输出数组C,以及三个计数器Aptr,Bptr,Cptr,计数器开始都被置于对应数组的开始端。A[Aptr]和B[Bptr]中的较小者被拷贝到C中的下一个位置,相关的计数器向前推进一步。当A和B俩个表中有一个用完时,则将另一个表中剩下的部分拷贝到C中。
归并排序是递归算法的很好的实例,也是经典的分治策略。将问题分解为一些较小的问题然后递归求解,治的阶段则将分阶段的解得的各个答案修补到一起。
我们将数组A中的1,13,24,26,2,15,27,38这8数用归并排序进行排序。
现将数组A一分为二,24,1,26,13为左组。27,15,38,2为右组,再格外使用一个临时数组C用来存放最终结果。
先将左组中的数据递归进行排序,再将右组中的数据递归进行排序,最后将俩组数据进行合并。
- 程序实现:
#include<iostream>
using namespace std;
void print(int a[], int n){
for(int j= 0; j<n; j++)
{
cout<<a[j] <<" ";
}
cout<<endl;
}
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1; //俩个指针,i左边数组的指针。j右边数组的指针
int m = mid, n = last; //m左边数组的边界,n右边数组的边界
int k = 0;
while (i <= m && j <= n)
{
if (a[i] <= a[j]) //总是将每半边中较小的一个数赋值给temp。
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i]; //重新将temp赋值给a
}
void mergesort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); //左边有序
mergesort(a, mid + 1, last, temp); //右边有序
mergearray(a, first, mid, last, temp); //再将二个有序数列合并
print(a, 8);
}
}
bool MergeSort(int a[], int n)
{
int *p = new int[n];
if (p == NULL)
return false;
mergesort(a, 0, n - 1, p);
delete[] p;
return true;
}
int main()
{
int a[8]={24,1,26,13,27,15,38,2};
MergeSort(a, 8);
system("pause");
}
- 程序实现分析:
MergeSort(a, 8);将数组a中的8个数进行排序。
1:开始
mergesort(a, 0, 7, p); 第一个数是a[0],第二个数是a[7],mid为3,
first < last
递归调用左边:mergesort(a, 0, 3, p);右边:mergesort(a, 4, 7, p);
2::mergesort(a, 0, 3, p);第一个数是a[0],第二个数是a[3],mid为1,
first < last
递归调用左边:mergesort(a, 0, 1, p);右边:mergesort(a, 2, 3, p);
3::mergesort(a, 0, 1, p);第一个数是a[0],第二个数是a[1],mid为0,
first < last
递归调用左边:mergesort(a, 0, 0, p);右边:mergesort(a, 1, 1, p);
4:左3:mergesort(a, 0, 0, p);第一个数是a[0],第二个数是a[0],mid为0,
first = last,结束。
右3:mergesort(a, 1, 1, p);第一个数是a[1],第二个数是a[1],mid为1,
first = last,结束。
5:返回上一层开始进行合并,上一层first为0,last为1,mid为0,
依次类推,递归求解各个部分,最后再合并起来。
整个递归调用示意图如下图所示,递归调用最后一层first=last,结束递归调用返回上一层进行mergearray(a, first, mid, last, temp);将左右两个数组合并。
- 时间复杂度为O(NlogN)归并排序很难用于主存排序,因为它在合并两个排序表时需要线性附加内存。