本文目的
上一章节已经详细的向大家介绍过排序的相关概念(详见学习笔记-排序简单介绍) ,本文旨在为大家详细的介绍归并排序。
归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路。归并排序是一种稳定的排序方法。
算法原理
归并具体工作原理如下(假设序列共有n个元素):
1,将序列每相邻两个数字进行归并操作,形成floor(n/2+n%2)个序列,排序后每个序列包含两个元素。
2,将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
重复步骤2,直到所有元素排序完毕
排序示例
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{94,19,29,9,11,1,14,13,29}
初始状态:{94,19,29,9,11,1,14,13,29}
第一次归并后:{19,94},{9,29},{1,11},{13,14},{29};
第二次归并后:{9,19,29,94},{1,11,13,14},{29};
第三次归并后:{1,9,11,13,14,19,29,94},{29};
第四次归并后:{1,9,11,13,14,19,29,29,94};
具体流程如下图:
算法描述
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经序列之和,该空间用来存放合并后的序列
第二步:设定两个,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
算法实现
#include #define elemType int /*元素类型*/int k=1;//轮次记录 //打印函数 void Print (elemType arr[], int len){int i;for (i=0; i a[j]) b[k++] = a[j++]; else b[k++] = a[i++]; } while(i != midIndex+1) b[k++] = a[i++]; while(j != endIndex+1) b[k++] = a[j++]; for(i=startIndex; i<=endIndex; i++) a[i] = b[i];} //内部使用递归void Sort(elemType a[], elemType b[], int startIndex, int endIndex){ int midIndex; if(startIndex < endIndex) { midIndex = startIndex + (endIndex-startIndex) / 2//避免溢出int Sort(a, b, startIndex, midIndex); Sort(a, b, midIndex+1, endIndex); Merge(a, b, startIndex, midIndex, endIndex); }}int main() {int i; elemType arr[9] = {94,19,29,9,11,1,14,13,29}; printf("待排序的序列为:"); Print(arr, 9); printf(""); elemType brr[9]; Sort (arr,brr,0,8); printf(""); printf("排好序的结果如下:"); Print(arr, 9); }
算法分析
时间复杂度
最坏情况下,当每两个待合并集合的元素大小呈现交叉形式时,需要比较的次数为两集合元素个数之和减一。即N个元素的集合,共需要比较的次数最多为:NlogN-N+1。故而时间复杂度为O(NlogN)。
最好情况下,当待合并的两个集合中,其中一个集合的最小元素大于另一个集合的最大元素时,需要比较的次数为其中一个集合的元素个数。即N个元素的集合,共需要比较的次数最多为:NlogN/2。故而时间复杂度为O(NlogN)。
无论是最好情况或者最坏情况下,每两个集合的合并操作都需要移动全部元素到临时集合中,再从临时集合中移动回原集合中,所以归并排序中元素的移动次数为:2NlogN,综上所述时间复杂度为O(NlogN)。
空间复杂度
归并排序中,用到了一个临时数组,故空间复杂度为O(N)
排序稳定性
归并排序是一种稳定排序算法,排序过程中,如果两个元素值相等,则不交换元素位置。对于
拓展
归并比较占用内存,但却是一种效率高且稳定的算法。
改进归并排序在归并时先判断前段序列的最大值与后段序列最小值的关系再确定是否进行复制比较。如果前段序列的最大值小于等于后段序列最小值,则说明序列可以直接形成一段有序序列不需要再归并,反之则需要。所以在序列本身有序的情况下时间复杂度可以降至O(n)
TimSort可以说是归并排序的终极优化版本,主要思想就是检测序列中的天然有序子段(若检测到严格降序子段则翻转序列为升序子段)。在最好情况下无论升序还是降序都可以使时间复杂度降至为O(n),具有很强的自适应性。
本文的初衷为学习笔记的分享,部分图文来源于网络,如侵,联删。