`

数据结构-排序: 两路归并排序算法

阅读更多

数据结构-排序: 两路归并排序算法

归并排序(Merge Sort)是利用"归并"技术来进行排序。归并是指将若干个已排序的子文件合并成一个有序的文件。

1、算法基本思路

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

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

(2)动态申请R1
 实现时,R1是动态申请的,因为申请的空间可能很大,故须加入申请空间是否成功的处理。

2、归并算法
void Merge(SeqList R,int low,int m,int high)
{//将两个有序的子文件R[low..m)和R[m+1..high]归并成一个有序的
//子文件R[low..high]
int i=low,j=m+1,p=0; //置初始值
RecType *R1; //R1是局部向量,若p定义为此类型指针速度更快
R1=(ReeType *)malloc((high-low+1)*sizeof(RecType));
if(! R1) //申请空间失败
Error("Insufficient memory available!");
while(i<=m&&j<=high) //两子文件非空时取其小者输出到R1[p]上
R1[p++]=(R[i].key<=R[j].key)?R[i++]:R[j++];
while(i<=m) //若第1个子文件非空,则复制剩余记录到R1中
R1[p++]=R[i++];
while(j<=high) //若第2个子文件非空,则复制剩余记录到R1中
R1[p++]=R[j++];
for(p=0,i=low;i<=high;p++,i++)
R[i]=R1[p];//归并完成后将结果复制回R[low..high]
} //Merge

归并排序有两种实现方法:自底向上和自顶向下。

1、 自底向上的方法
(1) 自底向上的基本思想
自底向上的基本思想是:第1趟归并排序时,将待排序的文件R[1..n]看作是n个长度为1的有序子文件,将这些子文件两两归并,若n为偶数,则得到 个长度为2的有序子文件;若n为奇数,则最后一个子文件轮空(不

参与归并)。故本趟归并完成后,前 个有序子文件长度为2,但最

后一个子文件长度仍为1;第2趟归并则是将第1趟归并所得到的 个有

序的子文件两两归并,如此反复,直到最后得到一个长度为n的有序文件为止。
上述的每次归并操作,均是将两个有序的子文件合并成一个有序的子文件,故称其为"二路归并排序"。类似地有k(k>2)路归并排序。

(2) 二路归并排序的全过程 (略)

(3) 一趟归并算法
分析:
在某趟归并中,设各子文件长度为length(最后一个子文件的长度可能小于length),则归并前R[1..n]中共有 个有序的子文件:R

[1..length],R[length+1..2length],…,
注意:
调用归并操作将相邻的一对子文件进行归并时,必须对子文件的个数可能是奇数、以及最后一个子文件的长度小于length这两种特殊情况进行特殊处理:
  ① 若子文件个数为奇数,则最后一个子文件无须和其它子文件归并(即本趟轮空);
  ② 若子文件个数为偶数,则要注意最后一对子文件中后一子文件的区间上界是n。

具体算法如下:
void MergePass(SeqList R,int length)
{ //对R[1..n]做一趟归并排序
int i;
for(i=1;i+2*length-1<=n;i=i+2*length)
Merge(R,i,i+length-1,i+2*length-1);
//归并长度为length的两个相邻子文件
if(i+length-1<n) //尚有两个子文件,其中后一个长度小于length
Merge(R,i,i+length-1,n); //归并最后两个子文件
//注意:若i≤n且i+length-1≥n时,则剩余一个子文件轮空,无须归并
} //MergePass

(4)二路归并排序算法
void MergeSort(SeqList R)
{//采用自底向上的方法,对R[1..n]进行二路归并排序
int length;
for(1ength=1;length<n;length*=2) //做趟归并

MergePass(R,length); //有序段长度≥n时终止
}

注意:
自底向上的归并排序算法虽然效率较高,但可读性较差。

2、自顶向下的方法
采用分治法进行自顶向下的算法设计,形式更为简洁。

(1)分治法的三个步骤
设归并排序的当前区间是R[low..high],分治法的三个步骤是:
①分解:将当前区间一分为二,即求分裂点

②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;
③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。
递归的终结条件:子区间长度为1(一个记录自然有序)。

(2)具体算法
void MergeSortDC(SeqList R,int low,int high)
{//用分治法对R[low..high]进行二路归并排序
int mid;
if(low<high){//区间长度大于1
mid=(low+high)/2; //分解
MergeSortDC(R,low,mid); //递归地对R[low..mid]排序
MergeSortDC(R,mid+1,high); //递归地对R[mid+1..high]排序
Merge(R,low,mid,high); //组合,将两个有序区归并为一个有序区
}
}//MergeSortDC

(3)算法MergeSortDC的执行过程 (略)
算法MergeSortDC的执行过程如下图所示归树。
二、算法分析

1、稳定性

 归并排序是一种稳定的排序。

2、存储结构要求
 可用顺序存储结构。也易于在链表上实现。

3、时间复杂度
 对长度为n的文件,需进行 趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。

4、空间复杂度
  需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
注意:
 若用单链表做存储结构,很容易给出就地的归并排序

分享到:
评论

相关推荐

    数据库系统实现-两阶段多路归并排序算法的C实现

    两阶段多路归并排序算法是一种常用于数据库管理系统中的高效排序方法。本文将深入探讨这个算法,并结合C语言的实现来阐述其工作原理。 首先,我们要理解什么是归并排序。归并排序是一种基于分治思想的排序算法,它...

    三路归并_C语言_三路归并排序_三路归并_

    **三路归并排序**是一种高效的排序算法,尤其在处理含有大量重复元素的序列时表现优秀。该算法基于归并排序的思想,但将其分为三...在C语言中,通过合理的指针管理和递归结构,可以实现清晰且高效的三路归并排序算法。

    数据结构实验-排序算法

    排序算法则是数据结构中的重要部分,它们用于对一组数据进行有序排列。在这个实验中,我们将关注六种不同的排序算法:选择排序、冒泡排序、插入排序、基数排序以及快速排序和归并排序。下面是对这些排序算法的详细...

    直接插入排序 冒泡排序 快速排序 直接选择排序 堆排序 二路归并排序 C#源代码

    直接插入排序、冒泡排序、快速排序、直接选择排序、堆排序和二路归并排序是计算机科学中经典的排序算法,它们在数据处理和算法学习中占有重要地位。这些排序算法各有特点,适用场景不同,下面将逐一详细介绍,并结合...

    数据结构-归并排序.doc

    在数据结构-归并排序的实验中,重点是理解和实现二路归并排序算法,以及递归地处理数组的拆分和归并过程。** ### 1. 算法原理 归并排序的基本思想是将待排序的数据分成两个子序列,每个子序列都是有序的,然后将这...

    数据结构教学课件:第23讲 归并排序-基数排序.pdf

    例如,在描述中提到的2-路归并排序,就是每次将两个子序列合并成一个新的有序序列,直到只剩下一个序列,即完全排序的序列。 归并排序的过程可以分为以下步骤: 1. 分解:将序列分成两个子序列,每个子序列包含一半...

    数据结构与算法分析(Java英文版)

    ### 数据结构与算法分析(Java英文版)知识点详解 #### 一、概述 《数据结构与算法分析(Java英文版)》是一本介绍如何利用Java语言处理实际问题中的数据结构和算法的专业书籍。本书由Robert Lafore编写,通过丰富...

    数据结构讲义

    - 定义:利用堆这种数据结构所设计的一种排序算法。 - 时间复杂度:O(n log n)。 - **归并排序** - 定义:把长度为n的输入序列分成两个长度为n/2的子序列,对这两个子序列分别采用归并排序,然后将两个排序好的子...

    归并排序 经典数据结构算法

    ### 归并排序:经典数据结构算法 #### 算法概述 归并排序是一种经典的、高效的基于比较的排序算法,其基本思想是采用分治法(Divide and Conquer)。该算法首先将待排序的序列分成若干个子序列,每个子序列都是...

    最常用的 8 个排序算法:从原理到改进,再到代码兑现透彻解析1

    - 二路归并:将两个已排序的子序列合并为一个有序序列。 - 算法介绍:采用递归方式,将大问题分解为小问题,然后逐步合并。 - 优点:稳定的排序算法,时间复杂度为O(n log n)。 - 缺点:需要额外的存储空间,...

    C++描述的数据结构

    - 外部排序:处理大数据量时,当内存不足以容纳所有数据时,需要使用外部排序算法,如多路归并排序。 - 搜索:二分查找适用于已排序的数组,而线性搜索适用于未排序的数组。 6. 字符串 - C++标准库中的`std::...

    数据结构课程设计(内部排序算法比较_C语言)

    ### 数据结构课程设计:内部排序算法比较_C语言 #### 一、课题背景与意义 排序作为数据结构中的重要组成部分,在实际开发中具有广泛的应用场景。理解不同排序算法的特点及其适用场景,对于提高程序效率和解决问题...

    数据结构-排序-PPT

    其中,插入类排序有直接插入排序和折半插入排序,交换类有冒泡排序和快速排序,选择类有简单选择排序和堆排序,归并类有2-路归并排序,分配类有基数排序和桶排序。 直接插入排序是一种简单直观的排序算法,它的基本...

    java数据结构和算法

    - 归并排序:分治策略,将数组分成两半分别排序后再合并,时间复杂度O(nlogn)。 - 堆排序:利用堆的特性进行排序,时间复杂度O(nlogn)。 2. **搜索算法** - 顺序搜索:依次检查每个元素,直到找到目标元素为止,...

    单链表为存储结构, 实现二路归并排序的算法

    通过这些步骤,我们可以实现一个在单链表上运行的二路归并排序算法,其时间复杂度为O(n log n),空间复杂度为O(1)(不考虑递归调用栈的空间)。`mergesort.txt`可能是这个算法的具体实现或示例数据,供进一步学习和...

    java算法大全源码包

    这个压缩包中包含了各种常见的算法实现,是学习和理解数据结构与算法的理想材料。以下将详细介绍其中可能涵盖的一些重要知识点: 1. **排序算法**: - 冒泡排序:一种简单的排序算法,通过重复遍历数组并交换相邻...

    数据结构与算法之排序

    在IT领域,数据结构与算法是基础且至关重要的部分,特别是排序算法,它们在软件开发中扮演着核心角色。本文将深入探讨“数据结构与算法之排序”,重点关注内部排序和外部排序。 首先,我们理解一下数据结构。数据...

    java算法-二路归并

    二路归并排序(Two-Way Merge Sort)是基于分治策略的一种排序算法。它将一个大问题分解为小问题,然后逐步解决,最终合并成解决方案。具体到二路归并排序,它将一个数组分为两个子数组,分别对它们进行排序,再将这...

Global site tag (gtag.js) - Google Analytics