归并排序

来源:互联网 发布:php管理上传文件 编辑:程序博客网 时间:2024/06/04 17:59

归并排序算法链接

排序思想

①  初始时,将每个记录看成一个单独的有序序列,则n个待排序记录就是n个长度为1的有序子序列;
②  对所有有序子序列进行两两归并,得到┏n/2┓个长度为2或1的有序子序列——一趟归并;
③  重复② ,直到得到长度为n的有序序列为止。
       上述排序过程中,子序列总是两两归并,称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为:
{R[k], R[k+1], …, R[m]}和{R[m+1], R[m+2],…, R[h]},将它们归并为一个有序的子序列:
{DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] }

排序示例

设有9个待排序的记录,关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41,归并排序的过程如图1所示。

算法实现

1. 非递归方式

/* 二路归并算法 *//* 将有序的R[low..mid]和X[mid+1..high]归并为有序的DR[low..high] */void Merge(int R[], int DR[], int low, int mid, int high){    int i, j, k;    i = k = low;    j = mid+1;    while(i<=mid && j<=high)    {        if(R[i] <= R[j])      /*  比较两个子序列 */            DR[k++] = R[i++];        else            DR[k++] = R[j++];    }    while(i<=mid)             /*  将R中剩余元素R[i...mid]复制到DR  */        DR[k++] = R[i++];    while(j<=high)            /*  将R中剩余元素R[j...high]复制到DR  */        DR[k++] = R[j++];}/*  一趟归并排序  */

/* 一趟归并排序都是从前到后,依次将相邻的两个有序子序列归并为一个,

/* 且除最后一个子序列外,其余每个子序列的长度都相同。 */

/* 设这些子序列的长度为d,则一趟归并排序的过程是: *//* 从j=0开始,依次将相邻的两个有序子序列R[j…j+d-1]和R[j+d…j+2d-1]进行归并;

/* 每次归并两个子序列后,j后移动2d个位置,即j=j+2d; */

/* 若剩下的元素不足两个子序列时,分以下两种情况处理: *//* ①  剩下的元素个数>d:再调用一次上述过程,将一个长度为d的子序列和不足d的子序列进行归并; *//* ②  剩下的元素个数≤d:将剩下的元素依次复制到归并后的序列中。 */

void Merge_pass(int R[], int DR[], int d, int n){    int j=0;    while ((j+2*d-1)<n)    {        Merge(R, DR, j, j+d-1, j+2*d-1);        j=j+2*d;    }                             /*   子序列两两归并  */    if(j+d-1<n)                   /*   剩余元素个数超过一个子序列长度d  */        Merge(R, DR, j, j+d-1, n);    else        Merge(R, DR, j, n, n);    /*   剩余子序列复制  */}

/* 开始归并时,每个记录是长度为1的有序子序列,对这些有序子序列逐趟归并,每一趟归并后有序子序列的长度均扩大一倍; */

/* 当有序子序列的长度与整个记录序列长度相等时,整个记录序列就成为有序序列。算法是: */

BOOL Merge_sort(int R[], int DR[], int length){    int d=1;    while(d<length)    {        Merge_pass(R, DR, d, length);        Merge_pass(DR, R, 2*d, length);        d=4*d;    }    return true;}

2. 递归方式

//将有二个有序数列R[low...mid]和R[mid+1...high]合并。void Merge(int R[], int low, int mid, int high, int temp[]){    int i, j, k;    i = k = low;    j = mid + 1;    while (i <= mid && j <= low)    {        if (R[i] <= R[j])            temp[k++] = R[i++];        else    temp[k++] = R[j++];    }    while (i <= mid)        temp[k++] = R[i++];    while (j <= high)        temp[k++] = R[j++];    for (i = 0; i < k; i++)        R[low + i] = temp[i];}void mergeSort(int R[], int low, int high, int temp[]){if (low < high){int mid = (low + high) / 2;mergeSort(a, low, mid, temp);    //左边有序mergeSort(a, mid + 1, high, temp); //右边有序Merge(a, low, mid, high, temp);  //再将二个有序数列合并}}bool MergeSort(int R[], int n){int DR[n] = {0};mergeSort(R, 0, n - 1, DR);return true;}

算法分析

具有n个待排序记录的归并次数是㏒2n,而一趟归并的时间复杂度为O(n),则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。在排序过程中,使用了辅助向量DR,大小与待排序记录空间相同,则空间复杂度为O(n)。归并排序是稳定的。

原创粉丝点击