算法分析与设计第四章2(分治法归并分类)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2) 过程MergeSort的分类时间用递推关系式表示如下:
a复杂度分n析=1,a是常数
T(n)=
O(1) 2T(n/2)+cn n>T1(,nc)是常数2T (n / 2) O(n)
n 1 递归调用一直进行
n
1
到子区间仅含一个 元素时为止
化简: 若n=2k,则有T, (n)=O(nlogn) 渐进意义下的最优算法
4,4,5
6,7,8
9,9,10
1,3,5
6,8,10
1,5,10
Merge的调用
2008-09-01
版权所有:杨波,武汉科技大学理学院
137190,228554,,127895,,65321,0,35315,1,42432,3,86415,0,25542,0 ,45605,25,20861
137190,285,311709,36512,63521
a[i] - 3 6 9 4 1 5
插入“4”:3<4<6,故6,9往
i
01 2 3 4 5 6
后移,4置于原6的位置
a[i] - 3 4 6 9 1 5
插入“1”:1<3,故3,4,6,9 i
01 2 3 4 5 6
均往后移,1置于原3的位置
a[i] - 1 3 4 6 9 5
插入“5”:4<5<6,故6,9 往后移,5置于原6的位置
分好类的序列 这样一个分类过程称为归并分类
2008-09-01
版权所有:杨波,武汉科技大学理学院
归并分类算法
void MergeSort(int low,int high) { //a[low:high]是一个全程数组,low和high分别指示当前待分类区
间的最小下标和最大下标,含有high-low+1≥0个待分类的元素
450
520
2008-09-01
版权所有:杨波,武汉科技大学理学院
2)归并过程
首先进入左分枝的划分与归并。 第一次归并前的划分状态是:
(310 | 285 | 179 | 652,351 | 423,861,254,450,520) 第一次归并:(285,310 | 179 | 652,351 | 423,861,254,450,520) 第二次归并:(179,285,310 | 652,351 | 423,861,254,450,520) 第三次归并:(179,285,310 |351,652 | 423,861,254,450,520) 第四次归并:(179,285,310,351,652 | 423,861,254,450,520)
例:用插入排序对6,9,3,4,1,5进行按非降分类起始数组:
i
01 2 3 4 5 6
a[i] - 6 9 3 4 1 5
插入“9”:9>6,故9 置于6之后
i
01 2 3 4 5 6
a[i] - 6 9 3 4 1 5
插入“3”:3<6,故6,9网 后移,3置于原6的位置
i
01 2 3 4 5 6
int i,j;
//循环计数变量
int item;
//欲插入数据变量
for(j=2;j<=n;j++) //a[1:j-1]Leabharlann Baidu分类好
{
item=a[j];i=j-1;
while(i>=1&&item<a[i])
{
a[i+1]=a[i];i=i-1;
}
a[i+1]=item;
}
}
i指示的是j之前的一位, 即当前已排序子表的 最末一个元素的下标
T(n) =2(2T(n/4)+cn/2)+cn
= 4T(n/4) + 2cn =4 (2T(n/8) +cn/4) + 2cn
=…
=2kT(1)+kcn
=an+cnlogn //k=logn
所以得:T(n) = O(nlogn)
2008-09-01
版权所有:杨波,武汉科技大学理学院
归并分类示例
设a=(310,285,179,652,351,423,861,254,450,520) 1)划分过程
//Link中值表示按分类次序给出a下标的表,并把p置于这表开始处
int i,t; //循环计数变量 i=1; //还有两段长度为DataLength的list可合并 while(i<=(n-2*DataLength+1)) {
Merge(i, i+DataLength-1, i+2*DataLength-1); i=i+2*DataLength; } if(i+DataLength<n) {//合并两段list,一段长度为DataLength,另一段长度不足DataLength Merge(i, i+DataLength-1, n); } else {//将剩下一段长度不足DataLength的list中的值不变 } }
if(a[h]<=a[j]) { b[i]=a[h];h++;} else {b[i]=a[j];j++;} i++; } if(h>mid) { for(k=j;k<=high;k++) { b[i]=a[k];i++; } } else { for(k=h;k<=mid;k++) { b[i]=a[k];i++; } } for(k=low;k<=high;k++) a[k]=b[k]; } }
2008-09-01
版权所有:杨波,武汉科技大学理学院
例:要排序的数据如下
步骤1:length=1 步骤2:length=2 步骤3:length=4
i 1 2 3 4 5 6 7 8 9 10 a[i] 9 8 7 6 5 4 3 2 1 0
i 1 2 3 4 5 6 7 8 9 10 a[i] 8 9 6 7 4 5 2 3 0 1
分类表可以通过Link的表头指针和读取Link中的链接关系取得。
2008-09-01
版权所有:杨波,武汉科技大学理学院
使用链接数组的归并分类模型
public static void MergeSort1(int low,int high,int p)
{//利用辅助数组Link[low:high]将全程数组a[low:high]按非降次序分 类。
}
}
2008-09-01
版权所有:杨波,武汉科技大学理学院
使用辅助数组归并两个已分类的集合的算法
public void Merge(int low,int mid,int high) {
int n,h,i,j,k; int b[]; n=a.length; b=new int[n]; h=low;i=low;j=mid+1; while((h<=mid)&&(j<=high)) {
第四章 分治法
2008-09-01
版权所有:杨波,武汉科技大学理学院
§4.4 归并分类
分类问题——排序
对一个给定含有n个元素(又称为关键字)的集合, 按一定次序进行分类(如非降次序)称n元排序。
常见的排序方法:
冒泡排序 插入排序 归并排序 快速排序
2008-09-01
版权所有:杨波,武汉科技大学理学院
再由b复制到a的对应位置上。
2008-09-01
版权所有:杨波,武汉科技大学理学院
2)改进措施
针对递归层次问题
采用能在小规模集合上有效工作的其它算法,直 接对小规模集合处理。
如InsertSort算法
针对元素频繁移动问题
采用一个称为链接信息数组Link[1:n]的数据结构, 记录归并过程中a的元素相对于其排序后在分类表中位 置坐标的链接关系。
版权所有:杨波,武汉科技大学理学院
改进的归并分类算法
1)算法存在的问题 递归层次太深
在MergeSort的执行过程中,当集合仅含有两 个元素时,仍要进一步做递归调用,直至每个集 合仅含有一个元素时才退出递归调用。
在集合含有仅相当少的元素时,较深层次的 递归调用使得时间过多地消耗在处理递归上。
元素在数组a和辅助数组b之间的频繁移动 每次归并,都要首先将a中的元素移到b中,
进入右分枝的划分与归并过程 (略)
2008-09-01
版权所有:杨波,武汉科技大学理学院
3)用树结构描述归并分类过程
1,10
1,5
6,10
1,3
4,5
6,8
9,10
1,2
3,3
4,4
5,5
6,7
8,8
9,9
10,10
1,1
2,2
6,6
7,7
MergeSort(1,10)的调用
1,1,2
6,6,7
1,2,3
插入分类
基本思想 for(j=2;j<=n;j++) {
将a[j]放到已分类集合a[1:j-1]的正确位置上 }
2008-09-01
版权所有:杨波,武汉科技大学理学院
public static void InsertionSort(int a[],int n)
{ //将a[1:n]中的元素按非降次序分类,n≥1
Link[i]取值于[1,n],是指向a的元素的指针:在 分类表中它指向下一个元素在a中的位置坐标。0表示 表的结束。
2008-09-01
版权所有:杨波,武汉科技大学理学院
例:
i
12 3 4 5 6 7 8
Link[i] 6 4 7 1 3 0 8 0
该表中含有两个子表,0表示表的结束。
设置表头指针Q和R分别指向两个子表的起始处:
int mid; if(low<high) //当含有2个及2个以上的元素时,作划分与递归处理
{ mid=(low+high)/2; //计算中分点 MergeSort(low,mid); //在第一个子集合上分类(递归) MergeSort(mid+1,high); //在第二个子集合上分类(递归) Merge(low,mid,high); //归并已分类的两子集合
2008-09-01
版权所有:杨波,武汉科技大学理学院
性能分析
输入数据按非增次序排列,每次内层while循 环执行j次(j=1,2,…, n-1)。
最坏情况: j (n 2)(n 1) / 2 (n2 ) 2 jn
最好情况: (n)
2008-09-01
版权所有:杨波,武汉科技大学理学院
245243,846213,,245540,,455200,,582601
137190,285,311709
36512,365512
238150,238150
179
310
285
652
351
245243,482631,826514
445500,520
423,861
254
423
861
450
520
2008-09-01
310,285,179,652,351,423,861,254,450,520
310,285,179,652,351
423,861,254,450,520
310,285,179
652,351
310,285
179
310
285
652
351
423,861,254
450,520
423,861
254
423
861
i 1 2 3 4 5 6 7 8 9 10 a[i] 6 7 8 9 2 3 4 5 0 1
i 1 2 3 4 5 6 7 8 9 10 a[i] 2 3 4 5 6 7 8 9 0 1
步骤4:length=8
2008-09-01
i 1 2 3 4 5 6 7 8 9 10 a[i] 0 1 2 3 4 5 6 7 8 9
Q=2,R=5;
则有,
表1:Q(2,4,1,6),经过分类后有:a[2]≤a[4]≤a[1]≤a[6]
表2:R(5,3,7,8),同样有:
a[5]≤a[3]≤a[7]≤a[8]
链接信息表在归并过程中的应用: 将归并过程中元素在a和b之间移动的过程变成更改Link所指示的
链接关系,从而避免移动元素的本身。
i
01 2 3 4 5 6
a[i] - 1 3 4 5 6 9
2008-09-01
版权所有:杨波,武汉科技大学理学院
分治策略设计
算法的基本思想 :
将 a[1], , a[n]分成两个集合a[1], , a[n / 2] 和 a[n / 2 1], , a[n]
对每个集合单独分类 将已分类的两个序列归并成一个含n个元素的
版权所有:杨波,武汉科技大学理学院
归并分类的非递归算法
设计思想
2008-09-01
版权所有:杨波,武汉科技大学理学院
2008-09-01
版权所有:杨波,武汉科技大学理学院
public static void MergeSort(int n,int DataLength) { //n为待合并数据个数
两个集合都没有取尽时, 将较小的元素先存 放到b中
如果前一个数
组中的元素 较小
如果后一个数
组中的元 素较小
将已归并的集 合复制到a 中
处理尚有剩余
元素的集 合
2008-09-01
版权所有:杨波,武汉科技大学理学院
性能分析
1) 过程Merge的归并时间与两数组元素的总数成正比
故可表示为: cn, n为元素数,c为某正常数