排序——归并排序(分治法)
2016-03-31 20:05
246 查看
在写归并排序之前,首先谈一谈分治的思想,
所谓分治:就是将一个比较复杂的问题分解为若干个规模较小的但是类似原问题的子问题,(解决)递归地求解这些这些子问题,再合并这些子问题的解来求解原问题
可分为三步:
分解:将原问题分解为若干个规模较小的但是类似原问题的子问题
求解:递归地求解这些这些子问题,然而若子问题规模足够小,可直接求解
合并:合并这些子问题的解来求解原问题
接下来,终于可以写归并排序了
分解:将一个有N个数的数列分解为2个分别有n/2个数的2个子数列
求解:使用归并排序递归地分别排序两个子数列;
合并:将两个子数列合并并排好序
根据上面的思路,归并排序的思路如下
分解:N可能为奇数可能为偶数,要充分考虑到,mergesort函数如下
注意,要考虑到p=r(p为一个数组中将要排序的起始项下标,r为一个数组中将要排序的终止项下标),若p=r,则根本不需要排序
,接下来,就是负责合并两个有序数列(注意:这里是一个循环不变式,先假设两个子数列都以排好序,起始:只有一个数,已排好序,不变:合并排序函数merge保证他们排好序,终止:递归结束),这里有两种方法:哨兵法和非哨兵法
哨兵法:所谓哨兵就是在L数列和R数列尾部分别添加一个近乎无穷大的数防止在判断L[i]和[j]时越界
非哨兵法:没有哨兵防止越界,就只能分 int n1=q-p+1 int n2=r-q int *L=(int*)malloc((n1+1)*sizeof(int)); int *R=(int*)malloc((n2+1)*sizeof(int));
以上是我的思考路程,附上一篇博文,归并写得比较好,参考
所谓分治:就是将一个比较复杂的问题分解为若干个规模较小的但是类似原问题的子问题,(解决)递归地求解这些这些子问题,再合并这些子问题的解来求解原问题
可分为三步:
分解:将原问题分解为若干个规模较小的但是类似原问题的子问题
求解:递归地求解这些这些子问题,然而若子问题规模足够小,可直接求解
合并:合并这些子问题的解来求解原问题
接下来,终于可以写归并排序了
分解:将一个有N个数的数列分解为2个分别有n/2个数的2个子数列
求解:使用归并排序递归地分别排序两个子数列;
合并:将两个子数列合并并排好序
根据上面的思路,归并排序的思路如下
分解:N可能为奇数可能为偶数,要充分考虑到,mergesort函数如下
void mergeSort(int* A,int p,int r) { if(p<r) { int q=(p+r)/2; mergeSort(A,p,q); mergeSort(A,q+1,r); merge(A,p,q,r); } }
注意,要考虑到p=r(p为一个数组中将要排序的起始项下标,r为一个数组中将要排序的终止项下标),若p=r,则根本不需要排序
,接下来,就是负责合并两个有序数列(注意:这里是一个循环不变式,先假设两个子数列都以排好序,起始:只有一个数,已排好序,不变:合并排序函数merge保证他们排好序,终止:递归结束),这里有两种方法:哨兵法和非哨兵法
哨兵法:所谓哨兵就是在L数列和R数列尾部分别添加一个近乎无穷大的数防止在判断L[i]和[j]时越界
int n1=q-p+1; int n2=r-q; int *L=(int*)malloc((n1+1)*sizeof(int)); int *R=(int*)malloc((n2+1)*sizeof(int)); int t,tmp1=0,tmp2=0; for(t=p;t<=q;t++) { *(L+tmp1)=*(A+t); tmp1++; } for(t=q+1;t<=r;t++) { *(R+tmp2)=*(A+t); tmp2++; } *(L+n1)=ShaoBing; *(R+n2)=ShaoBing; int i=0,j=0; int k; /* 依次从两个数字中取元素,将小的放入原数组中 */ for(k=p;k<=r;k++) { if(*(L+i)<=*(R+j)) { *(A+k)=*(L+i); i++; } else { *(A+k)=*(R+j); j++; } } free(L); free(R);
非哨兵法:没有哨兵防止越界,就只能分 int n1=q-p+1 int n2=r-q int *L=(int*)malloc((n1+1)*sizeof(int)); int *R=(int*)malloc((n2+1)*sizeof(int));
int t,tmp1=0,tmp2=0; for(t=p;t<=q;t++) { *(L+tmp1)=*(A+t); tmp1++; } for(t=q+1;t<=r;t++) { *(R+tmp2)=*(A+t); tmp2++; } *(L+n1)=ShaoBing; *(R+n2)=ShaoBing; int i=0,j=0; int k; /* 依次从两个数字中取元素,将小的放入原数组中 */ for(k=p;k<=r;k++) { if(i==n1) { while(j<n2) { *(A+k)=*(R+j); j++; k++; } break; } if(j==n2) { while(i<n1) { *(A+k)=*(L+i); i++; k++; } break; } if(*(L+i)<=*(R+j)) { *(A+k)=*(L+i); i++; } else { *(A+k)=*(R+j); j++; } } free(L); free(R);
以上是我的思考路程,附上一篇博文,归并写得比较好,参考
相关文章推荐
- GEEK学习笔记— —Linux常用命令
- Android Studio常用插件
- svn: Can't convert string from 'UTF-8' to native encoding:
- JSP内置对象——application对象
- 例子说冒泡排序
- 初始Oracle
- 野指针与内存泄露
- 格式化字符串
- HDOJ 2047-阿牛的EOF牛肉串【规律】
- viewpager
- 算法设计15-8签约棒球自由球员
- MySQL备份模式
- python 中文分词
- 地图坐标转换 -- 火星坐标与GPS坐标
- iOS开发:多线程技术概述
- JavaScript之DOM-6 BOM概述 、Window对象(Window对象概述、窗口与对话框、定时器)
- 除去链表中重复元素
- java反射机制
- Missing library: xdoclet-1.2.1.jar. Select the home directory for XDoclet. 1.2.1
- 蓝桥杯翻硬币