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

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

两阶段多路归并排序

Two-Phase Multiway Merge-Sort

实验报告

目录

1 实验目的 (3)

2 实验内容 (3)

3 实验环境 (3)

4 实验的设计和实现 (3)

4.1 算法描述 (3)

4.2 设计思路 (4)

4.3 数据结构 (5)

4.4 具体实现 (6)

5 实验结果 (9)

5.1 50MB内存TPMMS实验结果 (9)

5.2 10MB内存TPMMS实验结果 (9)

5.3 100MB内存TPMMS实验结果 (10)

5.4 三者的比较 (11)

6 实验遇到的问题和解决方法 (11)

6.1 Phase2阶段遇到的问题和解决方法 (11)

6.2 生成子记录文件名的方法 (13)

7 代码附录 (13)

1实验目的

通过merge-sort算法的实现,掌握外存算法所基于的I/O模型与内存算法基于的RAM模型的区别;理解不同的磁盘访问优化方法是如何提高数据访问性能的。

2实验内容

生成一个具有10,000,000个记录的文本文件,其中每个记录由100个字节组成。实验只考虑记录的一个属性A,假定A为整数类型。记录在block上封装时,采用non-spanned方式,即块上小于一个记录的空间不使用。Block的大小可在自己的操作系统上查看,xp一般为4096 bytes。在内存分配50M字节的空间用于外部merge-sort。要求设计和实现程序完成下列功能:

1)生成文本文件,其中属性A的值随机产生。

2)按照ppt中的方法对文本文件中的记录,按照属性A进行排序,其中在

第二阶段的排序中每个子列表使用一个block大小的缓冲区缓冲数据。

3)按照教材cylinder-based buffers(1M bytes)的方法,修改第二阶段的算法。

4)比较两种方法的时间性能,如果有更大的内存空间,算法性能还能提高

多少?

3实验环境

1)Visual C++ 6.0

2)Windows 7操作系统

4实验的设计和实现

4.1算法描述

Two-Phase Multiway Merge-Sort算法的具体描述分为2个阶段,如下所示:

●Phase 1

1)Fill main memory with records.

2)Sort with favorite main memory sorting algorithms.

3)Write sorted list to disk.

4)Repeat until all records have been put into one of the sorted lists.

●Phase 2

1)Initially load input buffers with the first block of their respective sorted

lists.

2)Repeated run a competition among the first unchosen records of each of

the buffered blocks.

3)If an input block is exhausted, get the next block from the same file.

4)If the output block is full, write it to disk.

4.2设计思路

从上述的算法描述中,我们知道,系统主要由2大模块组成:Phase1和Phase2。Phase1阶段主要将生成的记录文件按内存块大小(本实验中是50MB)分成多个(本实验中是20个)相应的子记录文件,把这些文件中的记录读进内存进行排序,再写回磁盘上。Phase2阶段利用多路归并排序算法,将Phase1阶段已经排好序的子记录文件重新归并为1个有序的记录文件,写回到磁盘上。由于我们在Phase1和Phase2阶段之前必须先生成1个含有10000000个100B记录的文件,所以系统必须再加上1个生成记录文件的Generate Record File模块。终上所述,系统由3大模块组成,分别为:Generate Record File、Phase1、Phase2。Phase1模块可以细分为内存块排序模块Main Memory Sort和写回磁盘模块Write To Disk。Phase2模块可以细分为多路归并排序模块Merge-Sort和写回磁盘模块Write To Disk。

详细的系统逻辑结构图如图3-1所示:

图3-1 TPMMS系统逻辑结构图

4.3数据结构

我们讨论单个记录的数据结构。由于1个记录有100个字节,其中4字节是由随机整数组成的主键属性Primary Key,另外96个字节是随意填充的数据content,而且本系统又是由C语言进行实现的,所以我们可以采取结构体来作为记录的数据结构。其中整形字段key记录4字节的主键属性,以便进行排序工作。数组字段contents用来填充剩余的96个字节,内容可以随意(本实验中均为0)。具体的数据结构如图4-1所示:

图4-1 单个记录的数据结构

4.4具体实现

4.4.1Generate Record File阶段

Generate Record File阶段比较简单,首先打开一个文件,然后生成随机数key并将其写入文件中,再填充96个任意内容的字节(本实验中均为0),即能生成1条完整的记录。重复10000000次,生成我们所需的记录文件。核心代码实现如图4-2所示,其中MAX_RECORD_NUMBER大小为10000000,ROW_NUMBER大小为95。

图4-2 Generate Record File阶段的实现

4.4.2Phase1阶段

Phase1阶段重点在于如何进行内存排序,并写回到磁盘上。这里我们采用了STL的sort函数帮助我们进行排序。首先读入50MB记录,利用sort 函数进行排序后,写到磁盘上生成1个有序的子记录文件。重复进行20次,生成20个相应的子记录文件。核心代码实现如图4-3所示,其中BLOCK_SIZE大小为50M,SUB_LIST_NUMBER大小为20。

图4-3 Phase1阶段的实现

4.4.3Phase2阶段

Phase2阶段是本系统实现的难点所在。主要的实现大致可以分为以下几部分进行讨论:

1)输入缓冲的实现

将Phase1阶段中得到的20个子记录文件的首字符分别读入长度为20的输入缓冲数组inputBuffer,核心代码实现如图4-4所示:

图4-4 输入缓冲的实现

2)输出缓冲的实现

选取输入缓冲数组inputBuffer中主键属性key最小的那个缓冲区,输入到输出缓冲数组outputBuffer中,然后循环执行,核心代码实现如图4-5所示:

图4-5 输出缓冲的实现

3)多路归并排序的实现

如果输出缓冲数组outputBuffer已经填满,此时可知输出缓冲是有序的,且之后的主键属性key的值都不会小于该输出缓冲区,这时我们即可将其输出到最后想要得到的结果文件上,核心代码实现如图4-6所示:

图4-6 多路归并排序的实现

4)Phase2阶段的其他实现

我们将在“实验中遇到的问题和解决办法”这一章详细讨论Phase2阶段剩下来的难点实现。

5实验结果

5.150MB内存TPMMS实验结果

采用50MB内存块大小进行TPMMS实验的结果如图5-1所示:

图5-1 50MB内存TPMMS实验结果图

从上图可以看出,生成1GB大小10000000条记录的文件需要152秒,phase1阶段需要136秒,phase2阶段需要150秒。所以整个排序过程需要286秒,即4分46秒的时间才能完成。

5.210MB内存TPMMS实验结果

我们将50MB内存缩减5倍,进行10MB内存块大小的TPMMS实验。这将

产生100个子记录文件。实验结果如图5-2所示:

图5-2 10MB内存TPMMS实验结果图

生成1GB大小10000000条记录的文件所需时间不变,仍为152秒左右。我们注重于phase1阶段和phase2阶段的所需时间。从图中可以看出,phase1阶段需要147秒,phase2阶段需要152秒。整个排序过程需要300秒,即5分钟的时间才能完成。

5.3100MB内存TPMMS实验结果

我们再将50MB内存增加2倍,进行100MB内存块大小的TPMMS实验。这将产生10个子记录文件。实验结果如图5-3所示:

图5-3 100MB内存TPMMS实验结果图

生成1GB大小10000000条记录的文件所需时间不变,仍为152秒左右。我们注重于phase1阶段和phase2阶段的所需时间。从图中可以看出,phase1阶段需要124秒,phase2阶段需要130秒。整个排序过程需要254秒,即4分14秒的时间才能完成。

5.4三者的比较

从上面的实验结果,我们可以很明显地看出,内存块大小越大,算法所需时间越少。这是因为内存块越小,生成的子记录文件个数就越多,这样phase1阶段生成子记录文件的时间就增加了。并且这还使得phase2阶段的输出缓冲区变小,导致多路归并时程序读写磁盘的次数增多,所以phase2阶段时间也增加了。这样整个排序过程时间当然增加。

终上所述,当在理想条件下,我们应使用内存块大小较大的方法来进行TPMMS算法的实现。在本章中TPMMS算法的性能为:100MB优于50MB优于10MB。所以在可能的情况下,应该考虑采纳100MB的TPMMS算法。

6实验遇到的问题和解决方法

6.1Phase2阶段遇到的问题和解决方法

前文已经详细描述了Phase2阶段的3个主要的实现阶段,但是仅仅依靠这3

个阶段还不能完全实现Phase2阶段,必须解决以下几个关键问题才能完成Phase2阶段的所有任务。

6.1.1读完某个子记录文件后,输入缓冲的填充方法

当某个输入缓冲数组inputBuffer[i]相对应的子记录文件infp[i]已经读完时,我们就必须重新查找其余可用的子记录文件,按数组下标i搜索到第一个可用的文件infp[k]后,将它的第一个字节继续填充到输入缓冲数组inputBuffer[i]中。

特别的,当数组下标i超过子记录文件总数SUB_LIST_NUMBER(本实验中为20)时,我们就认为所有子记录文件已经读取完毕,这时可以设置一个bool型变量flag = true,进行标识。核心代码实现如图6-1所示:

图6-1 读完某个子记录文件后,输入缓冲的填充方法

6.1.2读完所有子记录文件后,处理最后一组输入缓冲数据的方法

利用在6.1.1中设置的bool型变量flag,当flag=true时,我们知道子记录文件已经全部读取完毕。这时在输入缓冲数组inputBuffer中只剩下最后一组数据,并且根据Phase2阶段的定义,它们肯定比之前输入缓冲中的数据要大。所以我们只需利用STL提供的sort函数对它们进行排序后,直接输出到最终结果文件即可。核心代码实现如图6-2所示:

图6-1 读完所有子记录文件后,处理最后一组输入缓冲数据的方法

6.2生成子记录文件名的方法

当我们生成子记录文件时,想要赋予文件类似于record_k.txt (k = i+1, 0 <= i <= 19) 的文件名。由于在C语言中,不支持字符串和整数的直接连接。在这里我们需要一个generateFileName函数,采用itoa函数将整数k = i+1转换成字符串,再连接到“record_”后面,从而得到想要的文件名。核心代码实现如图6-3所示:

图6-3 生成子记录文件名的方法

7代码附录

#include // for sort function

#include // for strcpy

#include // for fscanf, fprintf, fopen

#include // for clock

using namespace std;

/* define the constants used in this program */

const int MAX_RECORD_NUMBER = 10000000; // max record number const int BLOCK_SIZE = 500000; // main memory block size const int ROW_NUMBER = 95; // for record to fill the other 96 bytes

const int SUB_LIST_NUMBER = ( MAX_RECORD_NUMBER / BLOCK_SIZE );

// sub list number

const int MAX = 99999999; // for function selectMinRecord to initialize the variable "min"

/* the data structrue of a record */

typedef struct record

{

int key; // primary key

char contents[ROW_NUMBER + 1]; // content

}Record;

Record subRecord[BLOCK_SIZE]; // main memory buffer

Record inputBuffer[BLOCK_SIZE + 1]; // input buffer

Record outputBuffer[BLOCK_SIZE + 1]; // output buffer

/* generate a file of MAX_RECORD_NUMBER (= 10000000) records, every record is 100 bytes */

void generateFile( string fileName )

{

// calculate time

printf("The records is now under generating ...\n");

clock_t start, finish;

double duration;

start = clock(); // start time

// open file

FILE *fp = fopen( fileName.c_str(), "w" );

if ( !fp ) // open failed

{

printf("File could not be created!\n");

fprintf( stderr, "File could not be created!\n" );

exit( 1 );

}

// generate random integers and records

srand( (unsigned)time( NULL ) ); // srand seed

for ( int i = 0; i < MAX_RECORD_NUMBER; i ++ ) // generate MAX_RECORD_NUMBER records

{

if ( i > 0 )

fprintf( fp, "\n" );

int key = rand(); // primary key, random integer, 4 bytes

// write record to disk, every record has 100 bytes

fprintf( fp, "%d ", key ); // write key as the first 4 bytes

for ( int j = 0; j < ROW_NUMBER; j ++ ) // write '0' for content as the other 96 bytes

fprintf( fp, "%c", '0' );

}

fclose( fp ); // close output file

// calculate time

finish = clock(); // finish time

duration = (double)( finish - start ) / CLOCKS_PER_SEC; // run time

printf ( "It takes %f seconds to genetate the whole records.\n", duration );

}

/* use for phase 1 of two phase multiway merge sort

compare two record by primary key, with ascending order */

bool cmp( const Record &r1, const Record &r2 )

{

return r1.key < r2.key;

}

/* give an integer, to generate a file name */

string generateFileName( int i )

{

char str[20]; // temporary charater array

string temp = ""; // temporary string

itoa( i+1, str, 10 ); // store integer k+1 to array str

temp = str; // convert array str to temporary string temp = "D:/record_" + temp + ".txt"; // form the file name

return temp; // return the temporary string of file name

}

/* phase 1 of two phase multiway merge sort

read record with maximum block size to main memory

and sort them by primary key */

void phase1( string fileName )

{

// open file

FILE *infp = fopen( fileName.c_str(), "r" );

if ( !infp ) // open failed

{

printf( "File %s could not be opened!\n", fileName.c_str() );

fprintf( stderr, "File %s could not be opened!\n", fileName.c_str() ); exit( 1 );

}

string temp = ""; // temporary string

int i = 0, j = 0;

// calculate time

printf( "The sorted list of records is now under generating ...\n" ); clock_t start, finish;

double duration;

start = clock(); // start time

char str[ROW_NUMBER + 10];

// read all records to main memory

for ( int k = 0; k < SUB_LIST_NUMBER; k ++ )

{

// read records of a block size to main memory

for ( i = 0; i < BLOCK_SIZE; i ++ )

{

fgets( str, ROW_NUMBER + 10, infp );

sscanf( str, "%d %s", &subRecord[i].key, subRecord[i].contents ); }

// use STL algorithm sort to sort records

sort( subRecord, subRecord + BLOCK_SIZE, cmp );

temp = generateFileName( k ); // sorted list name

FILE *outfp = fopen( temp.c_str(), "w" ); // open output file

if ( !outfp ) // open failed

{

printf( "File %s could not be opened!\n", temp.c_str());

fprintf( stderr, "File %s could not be opened!\n", temp.c_str() );

exit( 1 );

}

// write the sorted records to sub list file

for ( i = 0; i < BLOCK_SIZE; i ++ )

{

if ( i > 0 )

fprintf( outfp, "\n" );

fprintf( outfp, "%d %s", subRecord[i].key, subRecord[i].contents );

}

printf( "The sorted list %s generated successfully!\n", temp.c_str() );

fclose( outfp ); // close output stream

}

fclose( infp ); // close input file

// calculate time

finish = clock(); // finish time

duration = (double)( finish - start ) / CLOCKS_PER_SEC; // run time

printf( "It takes %f seconds to genetate the sorted list of records.\n", duration ); }

/* copy record r2 to record r1 */

void copyRecord( Record &r1, Record &r2 )

{

r1.key = r2.key;

strcpy( r1.contents, r2.contents );

}

/* copy a record to input buffer */

void copyToInputBuffer( FILE *fp, int index )

{

char str[ROW_NUMBER + 10];

fgets( str, ROW_NUMBER + 10, fp );

sscanf( str, "%d %s", &inputBuffer[index].key, inputBuffer[index].contents ); }

/* write the records in output buffer to disk

when the output buffer is full */

void writeToDisk( FILE *fp )

{

// flush output buffer to disk

for ( int j = 0; j < BLOCK_SIZE; j ++ )

{

fprintf( fp, "%d %s\n", outputBuffer[j].key, outputBuffer[j].contents );

}

}

/* select the minimum record in input buffer

by primary key */

int selectMinRecord( int size )

{

int min = MAX;

int index = 0;

for ( int i = 0; i < size; i ++ )

{

if ( inputBuffer[i].key < min )

{

min = inputBuffer[i].key;

index = i;

}

}

return index;

}

/* phase 2 of two phase multiway merge sort

merge the sorted sub list to a sorted result file

of ascending order */

void phase2()

{

// open output file to store the sorted records

FILE *outfp = fopen( "D:/result.txt", "w" );

if ( !outfp ) // open failed

{

printf( "Output file could not be created!\n" );

fprintf( stderr, "Output file could not be created!\n" );

exit( 1 );

}

string temp = ""; // temporary string

int count = 0; // the used output buffer size

int total = 0; // the record number written to disk int i = 0, j = 0;

简单的归并排序算法例子

import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; public class GuiBing { public static void main(String[] args) throws Exception { int datalength=1000000; GuiBing gui=new GuiBing(); int[] array1=gui.createArray(datalength); int[] array2=gui.createArray(datalength); Thread.sleep(20000); long startTime = System.nanoTime();//纳秒精度 long begin_freeMemory=Runtime.getRuntime().freeMemory(); int[] final_array=gui.guibing(array1,array2); boolean result=gui.testResult(final_array); long end_freeMemory=Runtime.getRuntime().freeMemory(); System.out.println("result===="+result); long estimatedTime = System.nanoTime() - startTime; System.out.println("elapsed time(纳秒精 度):"+estimatedTime/100000000.0); System.out.println("allocated memory:"+(begin_freeMemory-end_freeMemory)/1000.0+" KB"); Thread.sleep(20000); } /** * 显示数组的内容 * @param array */ private static void dispalyData(int[] array) { for(int i=0;i

归并排序算法实现 (迭代和递归)

归并排序算法实现(迭代和递归)\递归实现归并排序的原理如下: 递归分割: 递归到达底部后排序返回: 最终实现排序: #include void merge(int *array, int low, int center, int high) { if(low >= high) return; int m = center - low + 1; int n = high - center; int L[m], R[n]; for(int i=0; i R[j]) array[k] = R[j++]; else array[k] = L[i++];

} while(i #include

归并排序分治策略的设计与实现

实验名称归并排序分治策略的设计与实现实验方案实验成绩实验日期实验室信息系统设计与仿真室I 实验操作 实验台号班级姓名实验结果 一、实验目的 1、熟悉分治法求解问题的抽象控制策略; 2、熟悉在顺序存储表示下求解分类问题的递归算法设计; 3、通过实例转换, 掌握分治法应用。 二、实验任务 ①从文件中读取数据信息; ②利用归并排序算法,进行排序; ③输出排序结果。 三、实验设计方案 1、结构体设计 用数组存放排序数据。 2、自定义函数设计 ①函数原型声明 int input(int A[]); //从文件读入待排序的数据 void merge(int A[],int low,int mid,int high); // 两个相邻有序数组的归并 void mergesort(int A[],int low,int high); // 归并排序 void input(int A[], int n); // 输出排序结果 ②两个相邻的有序子数组的合并 思路:从两个已排好序的子数组的首元素开始,依次比较大小,按从小到大的顺序存放在b[]数组中,然后转存到A[]数组中。 void merge(int A[],int low,int mid,int high) { int b[N]; int i,j,k = 0; int l = low; //已排序部分1的起始下标 int h = mid+1; //已排序部分2的起始下标 while(l <= mid && h <= high) //两个有序部分合并到b数组中 if(A[l] < A[h]) b[k++] = A[l++]; else

数据结构实验-归并排序算法

大连理工大学实验预习报告 学院(系):电信专业:班级: 姓名:学号:组:___ 实验时间:实验室:实验台: 指导教师签字:成绩: 实验名称Merge sort 一、实验目的和要求 (一)、实验目的 Design the merge sort algorithm and implement it in C language 设计归并排序算法并于C语言实现。 (二)、实验要求 Requirements: 1) Analyze the time complexity of your algorithm 2) Submit the document explaining your algorithm as well as the source code. 要求: 1)分析算法的时间复杂度。 2) 提交的文档中说明你的算法和源代码。 二、实验原理 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可 解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了? 可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。

多路归并排序 外部排序算法

关于多路归并排序外部排序败者树技术积累2009-11-24 21:52:06 阅读453 评论0 字号:大中小 编程珠玑第一个case是有关一个技巧性解决外部排序问题的。问题很巧妙的解决了,但一开始提到的利用归并排序进行外部排序的算法仍值得仔细探究一下,毕竟本科时学的不是很深入。 先来看内部排序中最简单的2路归并排序算法。 算法核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列,给定数组中序列界限i、m、n,用2个下标变量分别从i和j=m+1开始逐个往后处理,先比较,小的写到结果序列的当前遍历下标k中,相应下标自增继续比较直到某个序列的下标走到边界,再将另外一个序列的剩余元素拷贝到结果序列中。 算法可用递归或递推实现,从相邻的两两元素开始不断调用上面的核心操作组成较长有序序列直到完成整个序列。 算法进行一趟归并就得到一个局部有序的完整新序列,n个元素共需要log2n趟归并,每趟完成比较操作n次(1次得到序列的1个值),得到的新序列写到结果序列空间中,下一趟之前要先将结果序列复制一份到临时空间,下一趟归并在临时空间上进行。因此时间复杂度nlog2n,空间上除了原始序列空间n、结果序列空间n,还需要辅助临时空间n。 接下来看外部排序。外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分,分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行多路归并排序。 多路归并排序算法在常见数据结构书中都有涉及。从2路到多路(k路),增大k可以减少外存信息读写时间,但k个归并段中选取最小的记录需要比较k-1次,为得到u个记录的一个有序段共需要(u-1)(k-1)次,若归并趟数为s次,那么对n个记录的文件进行外排时,内部归并过程中进行的总的比较次数为s(n-1)(k-1),也即(向上取整)(logkm)(k-1)(n-1)=(向上取整)(log2m/log2k)(k-1)(n-1),而(k-1)/log2k随k增而增因此内部归并时间随k增长而增长了,抵消了外存读写减少的时间,这样做不行,由此引出了“败者树”tree of loser的使用。在内部归并过程中利用败者树将k个归并段中选取最小记录比较的次数降为(向上取整)(log2k)次使总比较次数为(向上取整)(log2m)(n-1),与k无关。 败者树是完全二叉树,因此数据结构可以采用一维数组。其元素个数为k个叶子结点、k-1个比较结点、1个冠军结点共2k个。ls[0]为冠军结点,ls[1]--ls[k-1]为比较结点,ls[k]--ls[2k-1]为叶子结点(同时用另外一个指针索引b[0]--b[k-1]指向)。另外bk为一个附加的辅助空间,不属于败者树,初始化时存着MINKEY的值。 多路归并排序算法的过程大致为:首先将k个归并段中的首元素关键字依次存入

归并排序实验报告

篇一:归并排序与快速排序实验报告 一、实验内容: 对二路归并排序和快速排序对于逆序的顺序数的排序时间复杂度比较。 二、所用算法的基本思想及复杂度分析: 1、归并排序 1)基本思想:运用分治法,其分治策略为: ①划分:将待排序列 r1,r2,……,rn划分为两个长度相等的子序列 r1,……,rn/2和rn/2+1,……,rn。 ②求解子问题:分别对这两个子序列进行排序,得到两个有序子序列。 ③合并:将这两个有序子序列合并成一个有序子序列。 2)复杂度分析: 二路归并排序的时间代价是o(nlog2n)。二路归并排序在合并过程中需要与原始记录序列同样数量的存储空间,因此其空间复杂性o(n)。 2、快速排序: 1)基本思想:运用分治法,其分治策略为: ①划分:选定一个记录作为轴值,以轴值为基准将整个序列划分为两个子序列 r1……ri-1和ri+1……rn,轴值的位置i在划分的过程中确定,并且前一个子序列中记录的值均小于或等于轴值,后一个子序列中记录的值均大于或等于轴值。 ②求解子问题:分别对划分后的每一个子序列递归处理。 ③合并:由于对子序列r1……ri-1和ri+1……rn的排序是就地进行的,所以合并不需要执行任何操作。 2)复杂度分析: 快速排序在平均时间复杂性是o(nlog2n)。最坏的情况下是o(n^2)。 三、源程序及注释: 1、归并排序 #include<iostream> #include<fstream> #include windows.h using namespace std; void merge(int r[],int r1[],int s,int m,int t ) } int mergesort(int r[],int r1[],int s,int t) { } void main() int i=s; int j=m+1; int k=s; while(i<=m&&j<=t) {} if(i<=m)while(i<=m) r1[k++]=r[i++];//第一个没处理完,进行收尾if(r[i]<=r[j])r1[k++]=r[i++];//取r[i]和r[j]中较小的放入r1[k]中else r1[k++]=r[j++]; else while(j<=t) r1[k++]=r[j++];//第二个没处理完,进行收尾for(int l=0;l<k;l++) { } r[l]=r1[l];//将合并完成后的r1[]序列送回r[]中if(s==t)r1[s]=r[s]; else{int m; m=(s+t)/2; mergesort(r,r1,s,m);//归并排序前半个子序列 mergesort(r,r1,m+1,t); //归并排序后半个子序列 merge(r1,r,s,m,t);//合并两个已排序的子序列 }return 0; int a[100000]; int a1[10000];

归并排序算法的基本思想及算法实现示例

归并排序算法的基本思想及算法实现示例 归并排序(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=R1[p];//归并完成后将结果复制回R[low..high] } //Merge 归并排序 归并排序有两种实现方法:自底向上和自顶向下。

大文件内容排序,多路归并排序算法

package com.igo.util.file; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.slf4j.Logger; /** * * 外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存, * 需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。* 外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装人内存的部分, * 分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行归并排序。* @author ZhaoWeikai * Company: * 2010-12-23 下午02:25:00 */ public class MergeSort { private static final Logger log = org.slf4j.LoggerFactory.getLogger(MergeSort.class); /** 拆分大小, 单位:行*/ private static int SPLIT_SIZE = 100000; public static void main(String[] args) throws Exception { List list = FileUtil.listFiles("E:\\log\\test"); mergeFile(list, "e:/log/testMergeSort.txt"); } public static boolean mergeSort(List originFileList, String outPutFilePath, String tempPath) throws Exception { https://www.360docs.net/doc/cd10470088.html,("mergeSort start............................................."); FileUtil.createDir(tempPath); if (originFileList == null || originFileList.size() == 0) {

归并排序(非递归算法)

#include using namespace std; void Process(int n); void MergeSort(int ori[],int n); void newMerge(int ori[],int tmpArray[],int s,int n);//没有完成整个归并时,用这个函数归并两个相邻的已排序的数组 void Merge(int ori[],int tmpArray[],int left,int mid,int right); //归并两个已排好序的数组到tmpArray中 void Output(int op[],int n); //用来输出数组 int main() { int n; cin >> n; Process(n); return 0; } void Process(int n) { int ori[n+1]; for(int i = 1; i <= n; ++i) cin >> ori[i]; if( n > 1) //如果不止一个待排元素,就归并 MergeSort(ori,n); //原始调用MergeSort else Output(ori,n); } void MergeSort(int ori[],int n) { int s = 1,tmpArray[n+1]; //s是每趟归并两个数组时,一个数组的长度(最后那个数组长度可能小于s) while(s < n) { newMerge(ori,tmpArray,s,n); s *= 2; } } void newMerge(int ori[],int tmpArray[],int s,int n) { //没有完成整个归并时,用这个函数归并两个相邻的已排序的数组

归并排序算法论文

归并排序算法解决排序问题 目录 1引言 (2) 2.归并排序的基本思想 (2) 3.归并排序算法不同的方式 (3) 1.归并排序基本算法 (3) 1.实现过程 (3) 2.性能分析: (4) 2.递归二路归并排序 (5) 1.算法过程 (5) 2.性能分析: (6) 3.归并排序算法的改进算法 (7) 1.引理 (7) 2.应用例子 (7) 3.时间复杂性的分析 (8) 4.总结 (9) 5.参考文献 (9)

1引言 从归并排序的概念上进行分析,该算法的思想比较容易理解,并且也能够直观的感知其实质是利用存储空间的归并。在实现的过程中,可以有多种方法,画出归并过程示意图后,随即可以得出其算法的代码。但是我们在利用递归思想实现归并排序的教学程中,一定要让学生分清是用递归还是用回归进行的归并,画出图形区分这两种不同的归并过程。通过这一环节,我们不但能够理解稳定的归并排序,而且还让学生认清递归和回归是解决这一问题两种不同的操作过程。 2.归并排序的基本思想 归并排序主要是二路归并排序,它的基本思想是:设n个数据,初始时把他们看成n 个长度为l的有序子数组,然后从第—个子数组开始,把相邻的子数组两两归并,得到n/2个长度为2的新的有序子数组(当n为奇数是最后—个新的有序子数组长度为1);对这些新的有序子数组再两两归并;如此重复,直到得到—个长度为n的有序数组为止”。归并排序有两种实现方法:自顶向下和自底向上,前者定义是自底向上,

3.归并排序算法不同的方式 1.归并排序基本算法 1.实现过程 当初次理解归并概念的时候,我们可以列举下列一组数据的归并过程。例如:70 83 100 65 10 32 7 65 9 第一次:【70 83】【65 100】【10 32】【7 65】【9】 第二次:【65 70 83 100】【7 10 32 65】【9】 第三次:【7 10 32 65 65 70 83 100】【9】 第四次:【7 9 10 32 65 65 70 83 100】 具体程序代码如下: 函数:void merge(int e[],int n) 形参说明:e是已知待排序的数组,n是数组中元素的个数,下标从0开始。void merge(int e[],int n) { int +p=(int+)malloc(Sizeof(int)+n);/*开辟一块实现交替归并空间*/ int len=l,f=0;/*len为归并单元宽度,f是一个标识,实现交替归并*/while(1en=n)s end=n一1; /*确定真正末下标位置*/ merg_step(e,a,f_s,f_s+len-1,s_end);/*实现将两个单元合并*/

分治法实现归并排序算法算法设计与分析实验报告

算法设计与分析实验报告 实验名称分治法实现归并排序算法评分 实验日期年月日指导教师 姓名专业班级学号 一.实验要求 1.了解用分治法求解的问题:当要求解一个输入规模为n,且n的取值相当大的问题时,如果问题可以分成k个不同子集合,得到k个不同的可独立求解的子问题,其中1

then mid←, //求这个集合的分割点// call MERGESORT(low,mid) //将一个子集合排序// call MERGESORT(mid+1,high) //将另一个子集合排序 call MERGE(low,mid,high) //归并两个已排序的子集合// endif end MERGESORT 归并两个已排序的集合 procedure MERGE(low,mid,high) //A(low:high)是一个全程数组// //辅助数组B(low;high)// integer h,i,j,k; h←low;i←low;j←mid+1; while h≤mid and j≤high do //当两个集合都没取尽时// if A(h)≤A(j) then B(i) ←A(h);h←h+1 else B(i) ←A(j);j←j+1 endif i←i+1 repeat if h>mid then for k←j to high do //处理剩余的元素// B(i) ←A(k);i←i+1 repeat else for k←h to mid do B(i) ←A(k);i←i+1 repeat endif 将已归并的集合复制到A end MERGE 2. 快速排序算法 QuickSort(p,q) //将数组A[1:n]中的元素 A[p], A[p+1], , A[q]按不降次序排列, 并假定A[n+1]是一个确定的、且大于 A[1:n]中所有的数。// int p,q; global n, A[1:n]; if p

归并排序算法的原理及JAVA实现

归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为: 1)划分子表 2)合并半子表 首先我们来讨论归并算法,归并算法将一系列数据放到一个向量中,索引范围为[first,last],这个序列由两个排好序的子表构成,以索引终点(mid)为分界线,以下面一个序列为例 7,10,19,25,12,17,21,30,48 这样的一个序列中,分为两个子序列 7,10,19,25 和 12,17,21,30,48,如下图所示: 再使用归并算法的时候的步骤如下: 第一步:比较v[indexA]=7和v[indexB]=12,将较小的v[indexA]取出来放到临时向量tempArray中,然后indexA加1 第二步:比较v[indexA]=10和v[indexB]=12,将较小的10放到临时变量tempArray中,然后indexA++;

第三步:比较v[indexA]=19与v[indexB]=12,将较小的12存放到临时变量tempArray中,然后indexB++; 第四步到第七步:按照以上规则,进行比对和存储,得到如下结果: 最后一步:将子表b中剩余项添加到临时向量tempArray中 然后将临时变量中的值按照索引位置,拷贝回向量v中,就完成了对向量v 的归并排序 Java实现代码: package com.sort.merge; public class Merge { /** * 分治法,自顶向下,递归分割数组,最终归并 */ public static void merge(int[] arr,int start,int end){ if(start

归并排序算法

算法导论第一次上机报告 班级:1403018姓名:张可心学号:14030188030 (一)题目一 一、问题 Design aΘ(n lg n)-time algorithm that,given a set S of n integers and another integer x,determines whether or not there exist two elements in S whose sum is exactly x. 二、问题分析 集合S中有n个整数,给定一个整数x,设计一个算法,求出S中是否有两个元素相加之和为x。首先采用归并排序算法,复杂度为nlg n。再设计算法进行查找。 三、算法伪代码 merge(A,beg1,mid,end1) n1=mid-beg1+1 n2=end1-mid let A1[1..n1+1]andA2[1..n2+1]be new arrays for i=1to n1 A1[i]=A[beg1+i-1] for j=1to n2 A2[j]=A[mid+j] A1[n1+1]=∞ A2[n2+1]=∞ i=1j=1 for k=beg1to end1 if A1[i]≤A2[j] A[k]=A1[i] i=i+1else A[k]=A2[j] j=j+1 merge_sort(A,beg1,end1)

if beg1>n>>x for i=1to n cin>>A[i] i=i+1merge_sort(A,1,n) int i=1,j=n,t=0; while i!=j if A[i]+A[j]x j=j-1if A[i]+A[j]=x cout<<"YES"<

相关主题
相关文档
最新文档