归并排序运用分治法,先将无序序列不断分解,再将有序子序列逐层合并,得到完全有序序列。
归并排序的算法我们通常用递归实现,终止条件为分解到子区间只有一个元素。先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,默认单个元素不用排序。最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
归并细节:比较已排好序的左区间a[i]和右区间b[j]的大小,若a[i]≤b[j],则将左区间中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将右区间中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
归并排序时间复杂度为O(nlog₂n),空间复杂度为 O(n),比较占用内存,但却是一种效率高且稳定的算法。
C++实现代码如下:
//将data[]每层每个子序列已经排好序的左右区间的数据归并到result[]相应的下标中
void merge(int *data, int start, int end, int *result)
{
int mid = (start+end)/2;
int left_index = start;//左区间下标
int right_index = mid+1;//右区间下标
int result_index = start;
while (left_index <= mid && right_index <= end )
{
if (data[left_index] <= data[right_index])
result[result_index++] = data[left_index++];
else
result[result_index++] = data[right_index++];
}
while (left_index <= mid )
result[result_index++] = data[left_index++];
while (right_index <= end )
result[result_index++] = data[right_index++];
}
//注意每层每个子序列的start和end是不一样的
void merge_sort(int *data, int start, int end, int *result)
{
int mid = (start + end) / 2;
if (start == end)//划分到每个子序列只有一个元素结束
return;
else
{
merge_sort(data, start, mid, result);//划分每层每个子序列的左区间
merge_sort(data, mid + 1, end, result);//划分每层每个子序列右区间
merge(data, start, end, result);//开始归并每层每个子序列已经排好序的左区间和右区间,即该层start到end之间的数据,单个元素不用排序
for (int i = start; i <= end; ++i)//把排序后的区间数据复制到原始数据中去
data[i] = result[i];
}
}
int main()
{
int data[] = { 23,21,34,45,35,56,89,12 };
const int length = 8;
int result[length];
cout << "Before sorted:" << endl;
for (int i = 0; i < length; ++i)
cout << data[i] << " ";
cout << endl;
merge_sort(data, 0, length - 1, result);
cout << "After sorted:" << endl;
for (int i = 0; i < length; ++i)
cout << data[i] << " ";
cout << endl;
return 0;
}