算法导论 最坏情况为线性时间的选择算法 9.3-8 9.3-9
1.最坏情况为线性时间的选择算法
代码:
#include<iostream> #include<stdlib.h> using namespace std; //1.把n个元素按每组k个元素划分为upfloor(n/k)组(k>3),最后一组元素个数可能小于k个 //2.利用插入排序InsertSort找到每组中的中位数 //3.递归调用Select从步骤2中找到的中位数组中找出其中位数 int Select(int * A, int p, int r, int t); //插入排序,找到第t个顺序统计量 int InsertSort(int *A,int p,int r, int t) { for(int i=p+1;i<=r;i++) { int key=A[i]; int j=i-1; while(A[j]>key && j>=p) { A[j+1]=A[j]; --j; } A[j+1]=key; } return A[p+t-1]; } //找到中位数中的中位数 int Find(int *A,int p,int r,int k) { int len=r-p+1; int *B=new int[len/k+1];//存储步骤2找到的中位数 int j=0; int start=0, end=0; for(int i=0;i<len;i++) { if (i%k==0) start=p+i; if(i%k==k-1 || i==len-1) { end=p+i; B[j]=InsertSort(A,start,end,(end-start)/2); ++j; } } int mid=Select(B,0,j-1,j-1/2); delete []B; return mid; } //4.利用修改过的Partition版本,按中位数的中位数x对序列进行划分 //5.递归调用Select找到第t个顺序统计量 int Partition(int *A, int p, int r,int x) { int k=0; for (int i=p;i<=r;i++) { if (A[i]==x) k=i; } int temp1=A[r]; A[r]=A[k]; A[k]=A[r]; int l=p-1; for(int j=p;j<r;j++) { if(A[j]<A[r]) { ++l; int temp2=A[j]; A[j]=A[l]; A[l]=temp2; } } int temp3=A[r]; A[r]=A[l+1]; A[l+1]=temp3; return l+1; } int Select(int * A, int p, int r, int t) { if (p==r) return A[p]; int k=5; int x=Find(A,p,r,k); int q=Partition(A,p,r,x); int n=q-p+1; if (n==t) return A[q]; else if (t<n) return Select(A,p,q-1,t); else return Select(A,q+1,r,t-n); } int main() { int A[100]={0}; for (int i=0;i<100;i++) A[i]=rand()%100; int res_i=Select( A, 0, 99, 50); cout<<res_i<<endl; return 0; }
2.应用: 9.3-8
问题:两个包含n个有序元素的数组X,Y,设计一个O(lgn)时间的算法来找出数组X,Y中所有2n个元素的中位数。
思路:看到lgn,想到用分治法来做。分别调用Select找到X,Y的中位数midX,midY,若midX=midY,则中位数即为midX;若midX<midY,则对X的后半段和Y的前半段组成的两个数组递归找中位数;若midX>midY,则对X的前半段和Y的后半段组成的两个数组递归找中位数;直至,两个数组分别剩下两个元素,即总共有四个元素时,用插值法找到中位数。
代码:
int TwoVector(int *A,int p1,int r1,int *B,int p2,int r2,int n) { if(r1==p1 && r2==p2)//基本情形我这里写了四种,感觉有点繁琐,不知道有没有更简便的方式 { if (A[p1]<B[p2]) return A[p1]; else return B[p2]; } if(r1==p1+1 && r2==p2) { int C[3]={0}; C[0]=A[p1];C[1]=A[r1]; C[2]=B[p2]; int mid=InsertSort(C,0,2,2); return mid; } if(r1==p1 && r2==p2+1) { int C[3]={0}; C[0]=A[p1]; C[1]=B[p2];C[2]=A[r2]; int mid=InsertSort(C,0,2,2); return mid; } if(r1==p1+1 && r2==p2+1) { int C[4]={0}; C[0]=A[p1];C[1]=A[r1]; C[2]=B[p2];C[3]=B[r2]; int mid=InsertSort(C,0,3,2); return mid; } int midA=Select(A,p1,r1,n/2); int midB=Select(B,p2,r2,n/2); if(midA==midB) return midA; else if(midA<midB) return TwoVector(A,p1+n/2,r1,B,p2,p2+n/2-1,n/2); else return TwoVector(A,p1,p1+n/2-2,B,p2+n/2,r2,n/2); } int main() { int A[50]={0},B[50]={0}; for (int i=0;i<50;i++) { A[i]=rand()%100; B[i]=rand()%100; } InsertSort(A,0,49,1); InsertSort(B,0,49,1); int res=TwoVector(A,0,49,B,0,49,50); cout<<res<<endl; return 0; }
3.应用:9.3-9
问题:见算法导论p125
思路:任意两点A,B连成的直线上,在两个点之间线段上任意取一点C,d(A,C)+d(B,C)最短且相等
把所有油田看成在一条纵轴上,只要管道取为所有y的中位数即可得到最小总长度。若n为奇数,主管道位置唯一。若n为偶数,管道在n/2和n/2+1之间的位置(包括两个端点),总长度都最小。
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 算法导论 Exercises 9.3-9
- 下一篇: 解决 PHPExcel 长数字串显示为科学计数