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++)
  {
    
  }
  
}

 

posted @ 2023-07-11 20:26  hbhhbh  阅读(15)  评论(0)    收藏  举报