归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,
每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
动态演示如下:
思路
分割->合并。
归并操作的工作原理如下:
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针达到序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
示例代码:
#include<iostream>
using namespace std;
void merge(int *a,int low,int mid,int high){
int i=low;//i,j是检测指针分别指向待归并数组的第一子序列和第二子序列的首元素
int j=mid+1;
int k=low;//k 是指向辅助数组的第一个元素
int *b= new int[high]();//动态创建一个辅助数组,并初始化为0
//int *b= new int[high];这样写的话 辅助数组是没有初始化的
while(i<=mid && j<=high)//两个表都未检测完,两两比较
if(a[i] <= a[j])//此处也算是归并排序稳定性的关键,不能用小于
b[k++]=a[i++];
else
b[k++]=a[j++];
while( i <= mid)//若只有第一个未检测完,复制剩下的元素
b[k++]=a[i++];
while( j <= high )//若只有第二个子序列未检测完,复制剩下的元素
b[k++] =a[j++];
for(i=low;i<=high;i++)//将辅助数组中的元素写入的原先进行归并排序的数组中
a[i]=b[i];
}
void mergeSort(int *a,int low,int high){
if(low < high){
int mid = (low + high)/2;//从中间划分两个子序列
mergeSort(a,low,mid);//从左侧子序列进行递归排序
mergeSort(a,mid+1,high);//从右侧子序列进行递归排序
merge(a,low,mid,high);//合并
}
}
void main(){
int a[]={4,3,2,1,6,7,5};// 用于测试的数据
cout<<"Before mergeSort:"<<endl;
for(int i=0;i<7;i++){
cout<<a[i]<<" ";
}
cout<<endl;
cout<<"After mergeSort"<<endl;
mergeSort(a,0,6);
for(int i=0;i<7;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
性能分析:
时间复杂度为O(nlogn) 这是该算法中最好、最坏和平均的时间性能。
空间复杂度为 O(n)
比较操作的次数介于(nlogn) / 2和nlogn - n + 1。
赋值操作的次数是(2nlogn)。归并算法的空间复杂度为:0 (n)
归并排序比较占用内存,但却效率高且稳定的算法。
有人对归并排序算法也进行了改进,相关链接如下:
欢迎转载,但请留下足迹!