“chaos”的算法--之归并排序

简介:

                 【 声明:版权所有,欢迎转载。  联系信箱:yiluohuanghun@gmail.com】

   归并排序(Merge sort)的基本思想是合并两个有序表,设有两个有序(升序)序列存储在同一数组中相邻的位置上,不妨设为A[l..m],A[m+1..h],将它们归并为一个有序数列,并存储在A[l..h]。

  归并排序的时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlog2n),空间复杂度为O(N),它是一种稳定的排序方法。归并排序在最坏的情况下都是O(NlogN)的时间复杂度,缺点是Merge的时候要有O(N)的额外的空间.

   整体来说,对于归并排序可以运用分而治之方法来解决排序问题,该问题是将n 个元素排成非递减顺序。分而治之方法通常用以下的步骤来进行排序算法:若n 为1,算法终止;否则,将这一元素集合分割成两个或更多个子集合,对每一个子集合分别排序,然后将排好序的子集合归并为一个集合。

   假设仅将n 个元素的集合分成两个子集合。现在需要确定如何进行子集合的划分。一种可能性就是把前面n- 1个元素放到第一个子集中(称为A),最后一个元素放到第二个子集里(称为B)。按照这种方式对A递归地进行排序。由于B仅含一个元素,所以它已经排序完毕,在A排完序后,只需要用程序中的函数insert将A和B合并起来。把这种排序算法与InsertionSort进行比较,可以发现这种排序算法实际上就是插入排序的递归算法。该算法的复杂性为O(n2)。把n个元素划分成两个子集合的另一种方法是将含有最大值的元素放入B,剩下的放入A中。然后A被递归排序。为了合并排序后的A和B,只需要将B添加到A中即可。假如用函数M a x来找出最大元素,这种排序算法实际上就是SelectionSort的递归算法。

204541604.png

分治思想:

  将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解建立原问题的解,归并排序完全遵循分治模式:

分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列

解决:使用归并排序递归地排序两个子序列

合并:合并两个已排序的子序列以产生已排序的答案

归并排序算法:

  归并排序算法的关键操作是“合并”步骤中两个已排序序列的合并。我们通过调用一个辅助过程merge(A, p, q, r, T)来完成合并,其中A是一个数组,p,q,r是数组下标,满足p <= q < r, T是一个辅助数组空间。该过程假设子数组A[p..q]和A[q+1..r]都已排好序。它合并这两个子数组形成单一的已排好的子数组并代替当前的子数组A[p..r]n

过程merge需要O(n)的时间,其中n = r – p + 1是待合并元素的总数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//将有二个有序数列a[first...mid]和a[mid...last]合并。
void  mergearray( int  a[],  int  first,  int  mid,  int  last,  int  temp[])
{
     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];
}

   现在,我们可以过程merge作为归并排序算法中的一个子程序来用。下面的过程mereg_sort(A, p, r)排序子数组A[p...r]中的元素。若p >= r,则该子数组最多有一个元素,所以已经排好序。否则,分解步骤简单地计算一个下标q,将A[p...r]分成两个子数组A[p...q]和A[q...r],前者包含n / 2个元素,后者包含n / 2个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void  mergesort( int  a[],  int  first,  int  last,  int  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);   //合并前后两部分
     }
}
int  MergeSort( int  a[],  int  n)
{
     int  *p =  new  int [n];
     if  (p == NULL)
         return  FALSE;
     mergesort(a, 0, n - 1, p);
     delete [] p;
     return  TRUE;
}

   当然了,每到这个时候我都会说一样的话,测试程序一定要写,在程序可控范围内一定要将测试程序补上。

1
2
3
4
5
6
7
8
9
10
11
int  main( int  argc,  char * argv[])
{
     int  i, array[] = {6, 2, 3, 1, 4, 5};
     MergeSort(array, 6);
     for  (i = 0; i < 6; i++)
     {
         printf ( "%d\t" , array[i]);
     }
     getchar ();
     return  0;
}

   下一篇貌似该堆排序了,但是对于堆排序我一直不是太懂,大致思路知道,但就是不太理解实际机制,过段时间在写吧。




     本文转自 驿落黄昏 51CTO博客,原文链接:http://blog.51cto.com/yiluohuanghun/1271618,如需转载请自行联系原作者



相关文章
|
2天前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
|
4月前
|
机器学习/深度学习 算法 搜索推荐
【初阶算法4】——归并排序的详解,及其归并排序的扩展
【初阶算法4】——归并排序的详解,及其归并排序的扩展
【初阶算法4】——归并排序的详解,及其归并排序的扩展
|
5天前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
7天前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
18 0
|
9天前
|
搜索推荐 Java Go
深入了解归并排序算法
深入了解归并排序算法
8 0
|
5月前
|
算法 前端开发 搜索推荐
前端算法之归并排序
前端算法之归并排序
32 0
|
2月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
39 0
|
2月前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
30 0
|
3月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
70 4
|
3月前
|
算法 搜索推荐 C#