归并排序

来源:互联网 发布:red hat linux 9 编辑:程序博客网 时间:2024/06/13 06:55

  •  概述:

并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divideand Conquer)的一个非常典型的应用。归并排序先分解要排序的序列,从1分成22分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据


#include <iostream> using std::cin; using std::cout; using std::endl; /**  * 合并两个子列中的数据到一个数组中,每个子列都是有序的从小到大排列  * @ l 左边界 r右边界   * @unsorted unsorted数组unsorted[l..r-1] 其中unsorted[r..mid-1] unsorted[mid..r-1]分别是有序的数组  * @sorted 过度数组  */ template<class T> static void Merge(T unsorted[] ,size_t l,size_t mid,size_t r,T sorted[]) { int i = l,j=mid; //声明iterator  int k =0; //同时从两个队列中获取最小的元素,直到其中一个为空 while(i<mid &&j<r) if(unsorted[i]>unsorted[j])    sorted[k++] = unsorted[j++]; else    sorted[k++] = unsorted[i++]; //整合非空的队列到数组中 while(i<mid) sorted[k++] = unsorted[i++]; while(j<r) sorted[k++] = unsorted[j++];    //将已经有序的队列重新放置到由原来的数组 for(int v=0;v<k;unsorted[l+v]=sorted[v++]); }template<class T>static void printArray(T* arr,size_t l,size_t r){for(int i=l;i<r;i++)std::cout<<arr[i]<<" ";}//递归进行归并排序 template<class T> static void MergeSort(T unsorted[],size_t l,size_t r,T sorted[]) { if(l+1<r) { size_t mid = (l+r)>>1;  MergeSort(unsorted,l,mid,sorted); MergeSort(unsorted,mid,r,sorted); Merge(unsorted,l,mid,r,sorted); } } void testMergeSort() { int arr[] = {1,3,5,67,4,23,5,7,3,6,4,33}; int lenght = sizeof(arr)/sizeof(int); int* sorted = new int[lenght]; cout<<"Before sorted:"; printArray(arr,0,lenght); cout<<"\n";MergeSort(arr,0,lenght,sorted);printArray(arr,0,lenght);delete[] sorted;    cout<<endl;int arr2[] = {4,1};lenght = sizeof(arr2)/sizeof(int);sorted = new int[lenght];cout<<"Before sorted:"; printArray(arr2,0,lenght); cout<<"\n";MergeSort(arr2,0,lenght,sorted);printArray(arr2,0,lenght);delete[] sorted;} int main() { testMergeSort(); return 1; }

  • 稳定性:

归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序是稳定的排序算法。

  • 复杂度分析:

Merge操作是线性的,也就是那个n,然后分治时候是T(n/2),所以公式是
T(n)=2T(n/2)+n

经过简单地数学推导就可以知道时间复杂度为O(nlogn)

空间复杂度O(n),用来作为过渡数组的

  • 另附python测试代码:

import randomimport timedef mergesort(seq):if len(seq) <= 1:return seqmid = len(seq) >> 1left = mergesort(seq[:mid])right = mergesort(seq[mid:])return merge(left, right)def merge(left, right):result = []i, j = 0, 0while i < len(left) and j < len(right):if left[i] <= right[j]:result.append(left[i])i += 1else:result.append(right[j])j += 1result += left[i:]result += right[j:]return resultif __name__ == '__main__':seqtarget = range(1,10**6)seq = seqtarget[:]time_result = []for i in range(10):random.shuffle(seq)start = time.clock()seq = mergesort(seq)end = time.clock()time_result.append(end - start)assert(seqtarget == seq)print time_resultprint "The avg sort 10^6 time is: %f" % (sum(time_result)/len(time_result))

Result:

The avg sort 10^4 time is: 0.038085The avg sort 10^5 time is: 0.476787The avg sort 10^6 time is: 6.205277The avg sort 10^7 time is: 82.397774


Hadoop出现之后,归并排序的变得更加流行,在分布式集群中运行归并排序算法,让原本望而生畏的归并排序算法变得更加浅显易懂。因此在此要感谢Hadoop的贡献者们。

0 0