归并排序是建立在归并操作上的一种有效的排序算法。该算法是
分治法(Divide and Conquer)的一个非常典型的应用。
可以看出合并有序数列的效率是比较高的,时间复杂度可以达到O(n)。
首先考虑如何将两个有序数列合并成一个有序序列?这个非常简单,只要比较两个数列的第一个数,谁小就先取谁,然后插入到新数列,再依次比较这两个数列剩余的数,谁小先把谁取出插入新数列,如果有数列为空,那直接将另一个数列的数据依次取出插入新数列即可。
//将有序数组a[]和b[]合并到c[]中
void MemeryArray(int a[], int n, int b[], int m, int c[])
{
int i, j, k;
i = j = k = 0;
while (i < n && j < m)
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
}
可以看出合并有序数列的效率是比较高的,时间复杂度可以达到O(n)。
解决了上面的有序数列合并问题,再来看归并排序,基本思路就是将数组分成两组A,B,如果这两组组内的数据都是有序的,那么就可以很方便的将这两组数据进行排序。
如何让这两组数据分别有序呢?可以将A,B组两组再各自分成两组。依次类推,如下图所示,当分出来的小组只有一个数据时,其实这个小组的是数据已经达到了有序(一个数怎么都是有序的,难道不是吗!),然后再合并相邻的两个小组(有序数组的合并问题)就可以了。综述,归并排序问题可以分成两步进行,首先通过递归的分解数列成有序数列,再合并有序数列就解决了问题(显然分而治之思想)。
动画演示:
兑现代码:
#include<iostream>
using namespace std;
//打印数组
template<typename T>
void printArray(T arr[],int n)
{
for (int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
//合并两个有序数组成一个有序数组
template<typename T>
void mergearray(T a[], int first, int mid, int last, T temp[])
{ //合并两数组 [first mid] [mid last]
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n)
{
if (a[i] <= a[j])
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];
}
template<typename T>
void mergesort(T a[], int first, int last, T 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); //再将两个有序数列合并
}
}
template<typename T>
bool MergeSort(T a[], int n)
{
T *p = new T[n];
if (p == NULL)
return false;
mergesort(a, 0, n - 1, p);
delete[] p;
return true;
}
int main()
{
int b[]={2,4,7,5,8,1,3,6};
char s[] = {'e','f','a','h','b'};
MergeSort(b,8);
MergeSort<char>(s,5);
printArray<char>(s,5);
printArray<int>(b,8);
system("pause");
return 0;
}