博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
归并排序基本原理及实现
阅读量:5235 次
发布时间:2019-06-14

本文共 3023 字,大约阅读时间需要 10 分钟。

一、归并(Merge)

1. 概念

将两个有序数列合并成一个有序数列,我们称之为“归并”。

 

2. 算法思路及实现

设两个有序的子序列(相当于输入序列)放在同一序列中相邻的位置上:array[low..m],array[m + 1..high],先将它们合并到一个局部的暂存序列 temp (相当于输出序列)中,待合并完成后将 temp 复制回 array[low..high]中,从而完成排序。

在具体的合并过程中,设置 i,j 和 p 三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较 array[i] 和 array[j] 的关键字,取关键字较小(或较大)的记录复制到 temp[p] 中,然后将被复制记录的指针 i 或 j 加 1,以及指向复制位置的指针 p 加 1。重复这一过程直至两个输入的子序列有一个已全部复制完毕(不妨称其为空),此时将另一非空的子序列中剩余记录依次复制到 array 中即可。

c语言实现如下:

void merge(int* array, int low, int mid, int high){    assert(array && low >= 0 && low <= mid && mid <= high);    int* temp = (int*)malloc((high - low + 1) * sizeof(int));    if (!temp) {        printf("Error:out of memory!");        return;    }    int i = low;    int j = mid + 1;    int index = 0;    while (i <= mid && j <= high) {        if (array[i] <= array[j]) {            temp[index++] = array[i++];        }        else {            temp[index++] = array[j++];        }    }    while (i <= mid) {        temp[index++] = array[i++];    }    while (j <= high) {        temp[index++] = array[j++];    }    memcpy((void*)(array + low), (void*)temp, (high - low + 1) * sizeof(int)) ;    free(temp);}

 

二、 归并排序(Merge Sort)概念

建立在归并操作上的一种排序算法,该算法是采用(Divide and Conquer)的一个非常典型的应用。

归并排序有多路归并排序、两路归并排序,可用与内排序,也可用于外排序,本文仅对内排序的两路归并方法进行讨论。

 

三、归并排序思路及实现

1. 从下往上的归并排序

  • 把n个记录看成n个长度为1的数列(因为长度为1,所以自然有序)。
  • 进行两两归并,得到n/2个长度为2的有序数列,再将这些数列两两合并,得到n/4个长度为4的有序数列,重复这个过程,直到合并成一个数列为止。

过程如下图所示:

C语言实现:

// 对 [0, length - 1] 做一趟归并长度为 n  的归并排序void merge_pass(int* array, int length, int n){    assert(array && length >= 1 && n >= 1);    int i;    int sortLength = 2 * n;    // 归并长度为 n 的两个相邻子序列    for(i = 0; i + sortLength - 1 < length; i = i + sortLength) {        merge(array, i, i + n - 1, i + sortLength - 1);    }    // 若 i + n - 1 < length - 1,则剩余一个子文件轮空,无须归并。    // 尚有两个子序列,其中后一个长度小于 n, 归并最后两个子序列。    if (length - 1 > i + n - 1) {        merge(array, i, i + n - 1, length - 1);    }}// 用分治法自下向上进行二路归并排序//void merge_sort(int* array, int length){    assert(array && length >= 0);    int n;    for(n = 1; n < length; n = (n << 1)) {        merge_pass(array, length, n);    }}

优点是效率高,缺点是代码可读性差。

 

2. 从上往下的归并排序

具体的实现有三个步骤:

  • 分解 -- 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
  • 求解 -- 递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。
  • 合并 -- 将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。

如下图所示:

C语言实现:

void merge_sort_dc_impl(int* array, int low, int high){    assert(array && low >= 0);    int mid;    if (low < high) {        mid = (low + high) >> 1;        merge_sort_dc_impl(array, low, mid);        merge_sort_dc_impl(array, mid + 1, high);        merge(array, low, mid, high);    }}// 用分治法自上向下进行排序void merge_sort_dc(int* array, int length){    assert(array && length >= 0);    merge_sort_dc_impl(array, 0, length - 1);}

 

四、时间复杂度及稳定性

1. 时间复杂度

长度为n的序列需要进行logn次二路归并才能完成排序(归并排序的形式其实就是一棵二叉树,需要遍历的次数就是二叉树的深度),而每趟归并的时间复杂度为O(n),因此归并排序的时间复杂度为O(nlogn)

 

2. 排序稳定性

所谓排序稳定性,是指如果在排序的序列中,存在两个相等的两个元素,排序前和排序后他们的相对位置不发生变化的话,我们就说这个排序算法是稳定的。

排序算法是稳定的算法。

 

五、参考

1.

2.

3.

(完)

转载于:https://www.cnblogs.com/harrymore/p/9119540.html

你可能感兴趣的文章
c# 协变和逆变的理解
查看>>
树莓派3下安装TL-WN722N无线网卡驱动
查看>>
餐点乐的项目进度11/28
查看>>
4、获取接口调用凭证
查看>>
ZigBee四种绑定 在TI Z-Stack和谈栈中应用
查看>>
Vos baskets Huarache Gripp Nike Air flow
查看>>
[Linux]Linux系统目录
查看>>
HDU3177 贪心
查看>>
『cdq分治和多维偏序问题』
查看>>
寒假练习 04
查看>>
CEF3开发者系列之外篇——IE中JS与C++交互
查看>>
sql小技巧
查看>>
全选特效并修改checkbox样式
查看>>
rest_framework ---APIView
查看>>
[BZOJ 3224] [Tyvj 1728] 普通平衡树
查看>>
Ogre中TerrainSceneManager
查看>>
接口的应用
查看>>
WAVECOM CDMA Modem 发送短信
查看>>
Shortest Prefixes
查看>>
Fermat’s Chirstmas Theorem (素数打表的)
查看>>