分治算法
Posted 路人姜。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分治算法相关的知识,希望对你有一定的参考价值。
大家都知道选择排序和冒泡排序,这两个排序都是双重for循环,时间复杂度为O(n^2),显然效率都是比较低的,而运用分治思想的归并排序和快速排序会更高效一些。
1、归并排序
1)原理:假设初始序列含有n个记录,则可以看成是n个有序子序列,每个子序列的长度为1,然后两两归并,得到[n/2]([x]表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法成为2路归并排序。(摘自《大话数据结构》)
可见其运用了典型的分治思想,①分解②求解③合并。刚开始学习这个算法时,我感觉分开排序和一起排序没什么区别,但在实现算法时,会发现n个一起排序的话要用双重for循环,而分开排再合并会高效的多,下面看一下实现的代码。
2)参考代码
#include <iostream> #include <cstdio> using namespace std; int a[10]={2,3,1,5,34,21,12,4,10,6}; int b[10]; void Merge(int a[],int s,int m,int e,int tmp[]); void Mergesort(int a[],int s,int e,int tmp[]); int main() { int size=sizeof(a)/sizeof(int); Mergesort(a,0,size-1,b); for(int i=0;i<size;i++){ printf("%d ",a[i]); } return 0; } void Mergesort(int a[],int s,int e,int tmp[]){ if(s<e){ int m=s+(e-s)/2; Mergesort(a,s,m,tmp); Mergesort(a,m+1,e,tmp); Merge(a,s,m,e,tmp); } } void Merge(int a[],int s,int m,int e,int tmp[]){ int p1=s; int p2=m+1; int p=0; while(p1<=m&&p2<=e){ if(a[p1]<a[p2]){ tmp[p++]=a[p1++]; } else{ tmp[p++]=a[p2++]; } } while(p1<=m){ tmp[p++]=a[p1++]; } while(p2<=e){ tmp[p++]=a[p2++]; } //注意e和s已经变了,刚开始写成了i<size for(int i=0;i<e-s+1;i++){ a[s+i]=tmp[i]; } }
根据原理得,这十个数会先一个和一个比,然后合成两个,然后两个和两个比,一直到合成十个排序就完成了。
3)时间复杂度推导:
摘自:http://www.icourse163.org/learn/PKU-1001894005#/learn/content?type=detail&id=1002874892&sm=1
中国大学MOOC程序设计与算法,郭炜
2快速排序
1)基本思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
其基本思想也是根据分治算法来的,分解,求解,合并。像归并排序一样光看原理,感觉看不出来该种排序的高效,其实我觉得算法的巧妙更多的是在程序每个细节的代码实现中。
2)参考代码
#include <iostream> #include <cstdio> using namespace std; int a[10]={29,2,3,12,9,76,34,16,7,45}; void QuickShort(int a[],int s,int e); int main() { QuickShort(a,0,9); for(int i=0;i<10;i++){ printf("%d ",a[i]); } return 0; } void QuickShort(int a[],int s,int e){//s指向要排序列的第一个元素,e指向最后一个 if(s>=e){//临界条件:当两个指针指向同一个数时,说明排完了 return; } int k=a[s];//让k等于s指向的值 int i=s; int j=e; while(i!=j){//下面比较的while循环不要忘了让j>i即得到前一半和后一半的下标,也是跳出下面循环的边界 while(j>i&&a[j]>k){//先从j指向的数开始和k比较,小于k就交换值 j--; } swap(a[i],a[j]); while(j>i&&a[i]<=k){//交换后k就变成了a[j]的值 i++; } swap(a[i],a[j]); } QuickShort(a,s,i); QuickShort(a,i+1,e); }
以上是关于分治算法的主要内容,如果未能解决你的问题,请参考以下文章