算法导论之二归并排序法

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

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

分解:将待排序的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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
算法导论是计算机科学中非常重要的一门课程,它涵盖了计算机算法的设计、分析与应用。期末复习是为了加深对所学知识的理解和掌握,为考试做好充分准备。 使用Python语言进行算法导论的复习是一种很好的选择。Python是一种强大且易于上手的编程语言,具有简洁的语法和丰富的库支持。下面是几个复习的重点: 1. 熟悉Python的基本语法和数据结构:掌握Python的基本数据类型如列表、字典和集合,并了解它们的操作与性能。 2. 掌握常见排序算法:复习插入排序归并排序、快速排序等常见的排序算法,并能够灵活应用它们解决实际问题。 3. 熟悉图算法:学习图的表示方法,以及广度优先搜索(BFS)和深度优先搜索(DFS)等基本的图算法。 4. 熟练应用动态规划算法:了解动态规划的基本思想,复习使用动态规划解决背包问题、最长公共子序列等典型问题。 5. 学习贪心算法:了解贪心算法的概念和特点,熟悉使用贪心算法解决活动选择、哈夫曼编码等问题。 6. 熟练掌握分治算法:复习分治算法的基本思想和应用,熟悉使用分治算法解决最大子数组和矩阵乘法等问题。 7. 复习基本的算法分析方法:熟悉时间复杂度和空间复杂度的概念,掌握算法的渐进分析方法。 在复习过程中,可以通过参考教材、课堂笔记和习题集等资料进行练习和巩固所学知识。此外,可以参考一些算法导论的相关网上资源和在线教育平台上的课程进行深入学习。最重要的是,要坚持刷题,多进行实际编码练习,巩固所学算法的理解和应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

mengrennwpu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值