chap2.递归与分治策略
二分搜索
int binary_search(int x) { int l=0; int r=n-1; while(l<=r) { int mid=(l+r)/2; if(x==p[mid]) { return mid; } if(x>p[mid]) { l=mid+1; } else r=mid-1; } return -1; }
合并排序O(nlogn)
自然合并排序
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define ll long long #define endl "\n" #define debug freopen("C:/Users/HBH/Desktop/1.txt","w",stdout); int n; int a[1000]; int b[1000]; void merge(int* c, int* d, int l, int m, int r)//类似合并有序链表 { int i = l; int j = m + 1; int k = l; while ((i <= m) && (j <= r)) { if (c[i] <= c[j]) { d[k++] = c[i++]; } else d[k++] = c[j++]; } if (i > m) { for (int q = j; q <= r; q++) { d[k++] = c[q]; } } else { for (int q = i; q <= m; q++) { d[k++] = c[q]; } } } void mergepass(int* x, int* y, int s)//按段合并 { int i = 0; while (i + 2 * s <= n) { cout << "l: " << i << " m: " << i + s - 1 << " r: " << i + 2 * s - 1 << endl; merge(x, y, i, i + s - 1, i + 2 * s - 1); i += 2 * s; } if (i + s < n) merge(x, y, i, i + s - 1, n - 1); else { for (int j = i; j <= n - 1; j++) { y[j] = x[j]; } } } void mergesort() { int s = 1; //将大小为s的组组合 while (s < n) { mergepass(a, b, s); for (int i = 0; i < n; i++) { cout << b[i] << " "; } cout << endl; s += s; mergepass(b, a, s); for (int i = 0; i < n; i++) { cout << a[i] << " "; } cout << endl; s += s; } } int main() { srand(time(0)); cin >> n; for (int i = 0; i < n; i++) { a[i] = rand() % 20; cout << a[i] << " "; } cout << endl; mergesort(); for (int i = 0; i < n; i++) { cout << a[i] << " "; } }
递归合并排序
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define ll long long #define endl "\n" #define debug freopen("C:/Users/HBH/Desktop/1.txt","w",stdout); int n; int a[1000]; int b[1000]; void merge(int* c, int* d, int l, int m, int r) { int i = l; int j = m + 1; int k = l; while ((i <= m) && (j <= r)) { if (c[i] <= c[j]) { d[k++] = c[i++]; } else d[k++] = c[j++]; } if (i > m) { for (int q = j; q <= r; q++) { d[k++] = c[q]; } } else { for (int q = i; q <= m; q++) { d[k++] = c[q]; } } } void copy(int *a,int *b,int l,int r) { for(int i=l;i<=r;i++) { a[i]=b[i]; } } void mergesort(int l,int r) { if(l<r) { int mid=(l+r)/2; mergesort(l,mid); mergesort(mid+1,r); merge(a,b,l,mid,r); copy(a,b,l,r); } } int main() { srand(time(0)); cin >> n; for (int i = 0; i < n; i++) { a[i] = rand() % 20; cout << a[i] << " "; } cout << endl; mergesort(0,n-1); for (int i = 0; i < n; i++) { cout << a[i] << " "; } }
快速排序O(nlogn)~O(n2)
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define ll long long #define endl "\n" #define debug freopen("C:/Users/HBH/Desktop/1.txt","w",stdout); int n; int a[1000]; int partition(int p,int r) { int i=p; int j=r+1; int x=a[p]; while(1) { while(a[++i]<x&&i<r);//以a[p]为基准,划分两块区域 while(a[--j]>x); if(i>=j) break; swap(a[i],a[j]); } a[p]=a[j];//a[j]是小于a[p]的,所以可以换来 a[j]=x; return j; } void quick_sort(int p,int r) { if(p<r) { int q=partition(p,r); quick_sort(p,q-1); quick_sort(q+1,r); } } int main() { srand(time(0)); cin >> n; for (int i = 0; i < n; i++) { a[i] = rand() % 20; cout << a[i] << " "; } cout << endl; quick_sort(0,n-1); for (int i = 0; i < n; i++) { cout << a[i] << " "; } }
关于随机化:
随机化仅仅是将每次基准的值跟中间交换,因为大概率最后基准是在中间,所以交换能提高效率。
线性时间选择:
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define ll long long #define endl "\n" #define debug freopen("C:/Users/HBH/Desktop/1.txt","w",stdout); int n; int a[1000]; int partition(int p,int r,int x) { int i=p; int j=r+1; while(1) { while(a[++i]<x&&i<r); while(a[--j]>x); if(i>=j) break; swap(a[i],a[j]); } a[p]=a[j]; a[j]=x; return j; } int select(int p,int r,int k) { if(r-p<75) { sort(a+p,a+r+1); return a[p+k-1]; } for(int i=0;i<=(r-p-4)/5;i++)//分组 { int x=select(p,p+(r-p-4)/5,(r-p-4)/10);//找到一个中位数就划分一遍 int ii=partition(p,r,x); int j=ii-p+1; if(k<=j) { return select(p,ii,k); } else return select(i+1,r,k-j); } } int main() { srand(time(0)); cin >> n; for (int i = 0; i < n; i++) { a[i] = rand() %50; cout << a[i] << " "; } cout<<endl; cout<<select(0,n-1,10)<<endl; sort(a,a+n); for (int i = 0; i < n; i++) { cout << a[i] << " "; } }
最接近点对问题

①选取二维平面的一条垂直平分线L:x=m作为分割线。
━其中m为S中各点x坐标的中位数,由此将S分割为S1={p∈S|px≤m}和S2={p∈S|px>m}。
②递归地在S1和S2上找出其最小距离d1和d2。
━现设d=min(d1,d2)。若S的最接近点对(p,q)之间的距离d(p,q)<d,则p必∈S1和q必∈S2。
③如果用符号P1和P2分别表示直线 L 的左右两边宽为d的区域,则p∈P1,q∈P2。
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define ll long long #define endl "\n" #define debug freopen("C:/Users/HBH/Desktop/1.txt","w",stdout); struct pointX { int id; double x,y; bool operator<=(const pointX&a)const { return x<=a.x; } }; struct pointY { int p; double x,y; bool operator<=(const pointY&a)const { return y<=a.y; } }; template<class type> double distance(type a,type b) { double x=a.x-b.x; double y=a.y-b.y; return sqrt(x*x+y*y); } int n; template<class type> void merge(type* c, type* d, int l, int m, int r)//类似合并有序链表 { int i = l; int j = m + 1; int k = l; while ((i <= m) && (j <= r)) { if (c[i] <= c[j]) { d[k++] = c[i++]; } else d[k++] = c[j++]; } if (i > m) { for (int q = j; q <= r; q++) { d[k++] = c[q]; } } else { for (int q = i; q <= m; q++) { d[k++] = c[q]; } } } void closest(pointX*x,pointY*y,pointY*z,int l,int r,pointX&a,pointX&b,double&d) { if(r-l==1)//分割到只有2个点 { a=x[l]; b=x[r]; d=distance(a,b); return; } if(r-l==2)//三个点 { double d1=distance(x[l],x[l+1]); double d2=distance(x[l+1],x[r]); double d3=distance(x[r],x[l]); if(d1<=d2&&d1<=d3) { a=x[l]; b=x[l+1]; d=d1; return ; } else if(d2<=d3) { a=x[l+1]; b=x[r]; d=d2; return; } else { a=x[l]; b=x[r]; d=d3; return ; } } int mid=(l+r)/2;//中间距离 int f=l; int g=mid+1; for(int i=l;i<=r;i++)//分割两个集合 { if(y[i].p>mid) { z[g++]=y[i]; } else z[f++]=y[i]; } closest(x,z,y,l,mid,a,b,d);//两个集合内递归找最小点对 double dr; pointX ar,br; closest(x,z,y,mid+1,r,ar,br,dr); if(dr<d)//距离更小的 { a=ar; b=br; d=dr; } merge(z,y,l,mid,r);//将y数组恢复 int k=l; for(int i=l;i<=r;i++) { if(fabs(y[mid].x-y[i].x)<d)//找距离中线距离比集合内点距离最小值小的,目的是看看有没有两个最小距离点是分别在两个集合内的可能 { z[k++]=y[i]; } } for(int i=l;i<k;i++) { for(int j=i+1;j<k&&z[j].y-z[i].y<d;j++) { double dp=distance(z[i],z[j]);//找两个集合之间的最小点对距离 if(dp<d) { d=dp; a=x[z[i].p]; b=x[z[i].p]; } } } } bool cpair(pointX*X,pointX&a,pointX&b,double&d) { if(n<2)return false; sort(X,X+n); pointY*Y=new pointY[n]; for(int i=0;i<n;i++) { Y[i].p=X[i].id; Y[i].x=X[i].x; Y[i].y=X[i].y; } sort(Y,Y+n); pointY*Z=new pointY[n]; closest(X,Y,Z,0,n-1,a,b,d); } int main() { srand(time(0)); cin >> n; for (int i = 0; i < n; i++) { } }

浙公网安备 33010602011771号