由于准备复习考研,趁闲暇时练练算法,偶然看到一篇归并排序的文章,提起了兴趣,于是捣腾一番,查阅了一些资料以及几位大神的博客,做以下记录。
参考资料:
白话经典算法系列之五 归并排序的实现
http://blog.csdn.net/morewindows/article/details/6678165
《大话数据结构》第9章 排序 9.8 归并排序(上)
http://www.cnblogs.com/cj723/archive/2011/04/25/2026751.html
《大话数据结构》第9章 排序 9.8 归并排序(下)
http://www.cnblogs.com/cj723/archive/2011/04/26/2026886.html
[数据结构]中要合并两个有序线性表时,每次取出头部较小的一个加入合并的表后面,再读其下一个,最后剩下的那个线性表中的所有元素全部加速合并表后面。
归:利用递归的思想,将一个数组、链表一直均等分割下去,直到每个组只剩下一个为止;
并:将之前分割后的数组两两之间合并,结果再两两合并....一直合并下去,直到只剩下一个数组。
#include <stdio.h> #include "list_sort.h" //merge a segment of an array, minimum at the first void merge1( int *arr, int first, int mid, int last, char *temp ) { int i = first; int j = mid + 1; int k = 0; while ( i <= mid && j <= last ) { if ( arr[i] < arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while ( i <= mid ) temp[k++] = arr[i++]; while ( j <= last ) temp[k++] = arr[j++]; for ( k = first; k <= last; k++ ) arr[k] = temp[k - first]; } //use temp to save memory void mergeSort1( int *arr, int first, int last, char *temp ) { if ( first < last ) { int mid = (first + last) / 2; mergeSort1 ( arr, first, mid, temp ); mergeSort1 ( arr, mid + 1, last, temp ); merge1 ( arr, first, mid, last, temp ); } } void merge_Array_Sort1(int *arr, int len) { char temp[len + 1]; mergeSort1(arr, 0, len - 1, temp); }
整个归并排序需要将数组拆分log2N次,即调用了log2N次递归函数。
每次递归都对N个数据进行了操作。所以,时间复杂度为:O(N*logN)
由于栈有log2N层,每一层总共要维护N个数据,所以空间复杂度也是:O(N*logN)
这样看来,其时间复杂度、空间复杂度并不高。
递归算法易于读懂、实现起来较为容易,但是其空间复杂度仍可进一步下降。所以我再用非递归的方法实现了归并排序。
#include <stdio.h> #include <stdlib.h> #include "list_sort.h" void merge2( int *arr1, int *arr2, int first, int mid, int last ) { int i = first; int j = mid + 1; int k = first; while ( i <= mid && j <= last ) { if ( arr1[i] < arr1[j]) arr2[k++] = arr1[i++]; else arr2[k++] = arr1[j++]; } while ( i <= mid ) arr2[k++] = arr1[i++]; while ( j <= last ) arr2[k++] = arr1[j++]; } //将arr1(长度为len),每段间隔为s,两两合并到arr2 void mergeSort2( int *arr1, int *arr2, int len, int s ) { int i = 0; int j = 0; int first; int mid; int last; //所有长度为s的分段两两合并 int times = len / (2 * s); for ( i = 0; i < times; i++ ) { first = 2 * i * s; mid = first + s - 1; last = first + 2 * s - 1; merge2( arr1, arr2, first, mid, last); } //倒数第二段长度为s,最后一段长度大于0、小于s int remain = len % (s * 2); first = 2 * times * s; if ( remain > s ) { mid = first + s - 1; last = len - 1; merge2( arr1, arr2, first, mid, last ); } else for( j = first; j < len; j++ ) arr2[j] = arr1[j]; } void merge_Array_Sort2( int *arr, int len ) { int i; int *temp = (int *)malloc(sizeof(int) * len); int s = 1; while (s < len) { mergeSort2 ( arr, temp, len, s ); s *= 2; for (i = 0; i < len; i++) { arr[i] = temp[i]; } } }
易得其空间复杂度为N。