归并排序

来源:互联网 发布:域名备案名称 编辑:程序博客网 时间:2024/06/04 17:55

归并排序是一种利用分治思想来排序的算法。其核心思想是

       不断合并有序数据,直到所有数据有序为止。

       这里介绍二路归并,即初始有序长度为1,然后两两归并,如果重复,直到所有元素有序。

       二路归并的递归算法比较简洁,但是实用性很差。因为它调用了递归栈,需要额外的空间log2n次,再加上需要与数据等长度的额外数组,所以空间复杂度是o(n),归并算法的时间复杂度是o(n),一共要归并log2n次,所以时间复杂度是o(nlog2n).

       和快速排序和堆排序相比,它的唯一优势是它是一个稳定的排序算法,即相等元素的顺序不会在排序之后改变。所以,我们一般不在内部排序之中使用二路归并,这里我们通过介绍它来体会分治思想,因为归并在外部排序中很有用。

递归版本

#include <stdio.h>#include <stdlib.h>#define MAX 2<<30-1  //32位有符号最大整数void merge(int a[], int left, int mid, int right){int i;int m = mid-left+1;//前半部分的长度int n = right - (mid+1)+1;//后半部分的长度int* arr1 = (int*)malloc(sizeof(int)*(m+1));//多分配一个位置给哨兵卫int* arr2 = (int*)malloc(sizeof(int)*(n+1));for (i=0; i<m+1; i++) arr1[i] = a[left+i];for (i=0; i<n+1; i++) arr2[i] = a[mid+i+1];arr1[m] = arr2[n] = MAX; //设置哨兵卫,防止边界条件的判断int p, q;p = q = 0;for (i=left; i<=right; i++){if (arr1[p] <= arr2[q]){a[i] = arr1[p];p++;}else{a[i] = arr2[q];q++;}}free(arr1);free(arr2);arr1 = arr2 = NULL;}void merge_sort(int a[], int left, int right){if (left < right){int mid = (left+right)/2;merge_sort(a, left, mid);merge_sort(a, mid+1, right);merge(a, left, mid, right);//合并}}int main(void){int a[] = {1, 2, 9, 0, 3, 4, 12, 1, -23, 12, -89, -123};int i;int size = sizeof(a)/sizeof(int);merge_sort(a, 0, size-1);for (i=0; i<size; i++)printf("%d ", a[i]);getchar();return 0;}

非递归版本

只是划分过程不一样,合并函数是一样的

void merge_sort(int a[], int n){     if (n > 1)     {     int size=1,low,mid,high;       while(size<=n-1)     {          low=0;          while(low+size<=n-1)          {               mid=low+size-1;               high=mid+size;               if(high>n-1)//第二个序列个数不足size                    high=n-1;                        merge(a,low,mid,high);//调用归并子函数               low=high+1;//下一次归并时第一关序列的下界          }          size*=2;//范围扩大一倍     }     }}


0 0