数据结构与算法:排序算法-3(归并排序法、基数排序法)

一、归并排序法

(一)算法设计思想

    分治法的思想是将一个难以解决的大问题分解成若干个规模较小的问题,然后逐个解决分而治之。分治法经常和递归结合运用,那么什么问题适合使用分治法来求解呢?一般来说满足下列3个条件:

(1)一个大问题可以分解成若干个子问题

(2)分解后的各个子问题互相独立

(3)子问题的解可以合并为原问题的解

分治法求解的步骤:

(1)分解问题:将待解决的问题分解为若干个相互独立、与原问题形式相同的子问题

(2)分治子问题:求解各个子问题。由于各个子问题与原问题形式相同,用尽可能简单的办法求解子问题

(3)合并:按照原问题的要求,将子问题合并成原问题的解

(二)分治算法的案例

1、归并排序

归并排序将待排序数组a[1..n]分成两个各含n/2个元素的子序列,然后对这个两个子序列进行递归排序,最后将这两个已排序的子序列进行合并,即得到最终排好序的序列

数组排序时,如果只有1个数,那么它本身就是有序的;如果有2个数,那么比较1次就完成排序。也就是说数越少排序越容易。如果一个数据文件比较大很难快速完成排序,这时候我们可以将很大的数据文件分解成较小的数列,直到剩下一个数时候其本身就有序,再把这些有序的数列合并在一起从而完成排序。假设有个待排序的数组{8,4,5,7,1,3,6,2}如下图所示:

由上图可知,首先将待排序的数组分成大小相同的子序列,然后再把子序列分解成大小相同的两个子序列,如此做法直到分解成一个元素为止。然后进行归并操作,将两个子序列合并成一个子序列并排序,如此循环直到所有元素都归并为一个有序序列为止

(1)问题分析

     本案例有2个重要的操作:分解操作和归并操作,也就是说需要设计2个主要的方法来实现分解操作和归并操作。其中分解操作情况比较好处理一些,可以通过递归对自身不断的调用分解。这里先主要说下归并的方法

【1】方法的定义及其说明

方法:void  merge(int  a[] , int low ,  int  mid ,int  high)

参数说明:

a[] :数组对象    

low:待合并的两个子序列的下届

heigh:待合并的两个子序列的上届

    mid:中间位置

【2】方法的实现过程

    首先有个临时数组b[]将排好序的数据放到临时数组: int *b = new int[a.length];然后设计3个变量辅助工作:int  i = low,j = mid + 1 ,index = 0,i和j指向两个待排序子序列中当前比较的元素,index指向辅助数组b[]中待放置元素的位置。比较a[ i ]和a[ j ]将较小的赋值给b[index],同时相应的索引i、j、k后移,循环处理直到所有元素处理完成,最后把排好序的数组b的元素复制到数组a中

    假设有个待排序的数组:{3,9,16,23,66,2,6,19,20},数据的初始化如下所示:

现在开始比较a[i]和a[ j ],将较小的元素放在数组b,相应的i , j ,index指针后移,直到 i > mid 或者j > high结束,代码如下:

while(i  >  mid ||  j  > high ){ //也可 i<=mid && j<=high

      if (a[i] < = a[ j ]){

          b[index++] = a [ i++];

      }else{

          b[index++] = a [ i++];

      }

}

下面详细描述下归并的过程:

第1次比较: a[ i] = 3  a[ j] = 2,将小的元素2放到数组b,指针移动j++,index++,大的那个数i指针就不需要移动

初始化:

比较结果:

第2次比较: a[ i] = 3  a[ j] =6,将小的元素3放到数组b,指针移动i++,index++,大的那个数j指针就不需要移动了

初始化:

比较结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数字化与智能化

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

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

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

打赏作者

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

抵扣说明:

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

余额充值