算法导论之二归并排序法

本文深入探讨了归并排序的分治思想及其操作步骤,包括分解、解决和合并过程。详细介绍了归并排序算法的核心原理及具体实现,通过伪代码和实际代码展示了如何运用辅助过程MERGE进行有序子数组的合并。同时,提供了归并排序算法的程序代码,通过实例演示了如何对数组进行排序。

分治法的思想是将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

归并排序算法完全遵循分治模式,操作步骤如下:

分解:将待排序的n个元素的序列分解为分别具有n/2个元素的两个子序列。

解决:使用归并排序递归地排序两个子序列。

合并:合并两个已排序的子序列以产生已排序的原序列。

“合并”操作中通过调用一个辅助过程MERGE(A,p,q,r)来完成,其中A是一个数组,p,q和r是数组下表,满足,该过程假设子数组A[p..q]和A[q+1..r]都已排好序。该过程合并这两个子数组形成单一的已排好序的子数组并代替当前子数组A[p..r]。

伪代码如下,需要注意,在每个子数组的末尾增加一张哨兵值,以避免在每个基本步骤中必须检查是否子数组为空:

MERGE(A,p,q,r)

n1 = q – p + 1             //计算子数组A[p..q]的长度n1

n2 = r – q                    //计算子数组A[q+1 ..r]的长度n2

//创建长度分别为n1+1和n2+1的数组L和R,数组的额外位置保存哨兵值

let L[1..n1+1] and R[1..n2+1] be new arrays  

for i = 1 to n1

  L[i] = A[p + i - 1]           //将子数组A[p..q]复制到L[1..n1]

for j = 1 to n2

  R[j] = A[q + j]       //将子数组A[q+1 ..r]复制到R[1..n2]

L[n1 + 1] =

R[n2 + 1] =           //将哨兵值放在数组L和R的末尾

i = 1

j = 1

//在开始循环的每次迭代时,子数组A[p..k-1]按从小到大的顺序依次包含L和R中的k-p个//最小元素,进而,L[i]和R[j]是各自所在数组中未被复制回数组A的最小元素

for k = p to r

if  L[i] <= R[j]

    A[k] =L[i]

    i = i + 1

else

   A[k] = R[j]

    j = j + 1

 

下面的过程MERGE-SORT(A,p,r)排序子数组中A[p..r]中的元素,其中将MERGE过程作为归并排序算法中的一个子程序来应用:

MERGE-SORT(A,p,r)

if  p< r

   q=

  MERGE-SORT(A,p,q)

  MERGE-SORT(A,q+1,r)

  MERGE(A,p,q,r)

 

程序代码如下:

#include "stdio.h"

#include "stdlib.h"

#define MAX 10

 

void print_array(int *array_test,unsignedint x)

{

         unsignedint i;

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

         {

                   printf("%d",array_test[i]);

         }

         printf("\n");

}

 

static void merge(int array[],int low,intmid,int high)

{

         inti,k;

 

         //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

         int*temp=(int*)malloc((high-low+1)*sizeof(int));

 

         intbegin1=low;        //左半边开始下标

         intend1=mid;  //左半边结束下标

         intbegin2=mid+1;   //右半边开始下标

         intend2=high; //右半边开始下标

 

         printf("mid=%d",mid);

 

         k=0;

 

         while(begin1<=end1 && begin2<=end2)

         {

                   //左右两边分别比较,并且一次存入临时数组

                   if(array[begin1]<array[begin2])

                   {

                            temp[k++]=array[begin1++];

                   }

                   else

                   {

                            temp[k++]=array[begin2++];

                   }

         }

 

         //若第一个序列有剩余,直接拷贝出来粘到合并序列尾

         while(begin1<=end1)

         {

                   temp[k++]=array[begin1++];

         }

 

         //若第二个序列有剩余,直接拷贝出来粘到合并序列尾

         while(begin2<=end2)

         {

                   temp[k++]=array[begin2++];

         }

 

         //将排序好的序列拷贝回数组中

         for(i=0;i<(high-low+1);i++)

         {

                   array[low+i]=temp[i];

         }

 

         printf("合并: ");

         print_array(array,MAX);

         free(temp);

}

 

void merge_sort(int array[],unsigned intfirst,unsigned int last)

{

         intmid=0;

         if(first<last)

         {

                   mid=(first+last)/2;

                   merge_sort(array,first,mid);   //划分左半部分

                   merge_sort(array,mid+1,last);        //划分右半部分

                   merge(array,first,mid,last);    //合并

         }

}

 

int main()

{

         intarray_test[MAX]={0,9,8,4,3,2,1,5,6,7};

         printf("start:");

         print_array(array_test,MAX);

         merge_sort(array_test,0,9);

         printf("end:");

         print_array(array_test,MAX);

         return0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mengrennwpu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值