Rockwall

导航

排序算法总结(二)归并排序【Merge Sort】

一.归并排序原理(Wikipedia)

  归并排序本质是分治思想的应用,并且各层分治递归可以同时进行

  1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

  2.设定两个指针,最初位置分别为两个已经排序序列的起始位置

  3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

  4.重复步骤3直到某一指针到达序列尾

  5.将另一序列剩下的所有元素直接复制到合并序列尾

二.过程

原始数据

seg = 1时

我的算法参考的是wikipedia上的算法,与VisuAlgo上所示的稍有区别,VisuAlgo上是先2个数字合并,然后合并成4个有序数列,然后在对后面的2个合并,在合并成4个有序数列,把这两组有序数列合并成一个长度为8的有序数列。

 

 

 

wikipedia上,是先将所有的单个数字合并成有序的长度为2的有序数组,然后在将所长度为2的分别合并成长度为4的有序数组,循环知道合成长度为Len的有序数组。个人认为wikipedia上的方法更加容易表达,因为不用回退可以一次性处理完所有相同长度的数据。

wikipedia上代码的排序过程如图所示:

 

3.代码(参考了wikipedia上的代码,只需要第一次分配一次空间)

 

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 template <typename T>
 7 void MergeSort( vector<T> & nums ) {
 8     int seg = 1;
 9     int len = nums.size(); 
10     vector<T> CopyNums(nums);
11     for(int seg = 1; seg < len; seg += seg ){
12         for(int start = 0; start < len; start += seg + seg ){
13             int low = start;
14             int mid = min( start + seg, len );//对于最后一次归并 
15             int high = min( start + seg + seg, len );//最后一次归并长度会大于len
16             int k = low;
17             int start1 = low;
18             int end1 = mid;
19             int start2 = mid;
20             int end2 = high;
21             while( start1 < end1 && start2 < end2 ){
22                 CopyNums[k++] = nums[start1]<nums[start2]? nums[start1++]:nums[start2++];
23             }
24             while( start1 < end1 ){
25                 CopyNums[k++] = nums[start1++];//如果start1后还有元素没有归并,则将start1后的元素进行归并 
26             } 
27             while( start2 < end2 ){
28                 CopyNums[k++] = nums[start2++];////如果start2后还有元素没有归并,则将start2后的元素进行归并  
29             }
30         }
31         nums.swap(CopyNums);//在C++ STL中,耗时是常量,因为实际并没有交换他们的值,而只是交换了指针。
32         //(i.e., the containers exchange references to their data, without actually performing any element copy or movement)37     }
38 } 
39 
40 int main(){
41     vector<int> nums{3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
42     cout<<" Before Sort:" ;
43     for( auto m: nums){
44         cout <<  m <<" ";
45     }
46     cout<<endl;
47     MergeSort( nums );
48     cout<< " After Sort:";
49     for( auto m: nums){
50         cout  << m <<" ";
51     }
52     cout<<endl;
53 }

 

4.总结

 

1.空间复杂度,因为只有开始分配了一次与原始数据相同长度的空间,所以空间复杂度为O(n);

2.时间复杂度,总的比较次数在(nlogn)/2和nlogn-n+1之间;

3.归并排序是稳定的排序算法。 

 

posted on 2016-08-05 15:56  Rockwall  阅读(1043)  评论(0编辑  收藏  举报