分治法{二分查找,归并排序,快速排序}

 

任务一 二分搜索及变形

(1)在有序数组里面查找是否存在某个元素x, 如果存在, 则返回相应元素所在索引号;如果不存在, 返回-1。分别用递归和非递归的方式实现。

算法描述:

① 将数组分成 l~m-1,m, m+1~r 三部分

② 如果a[m] 为所找值,算法结束;如果所求值小于a[m],将数组l~m-1部分继续操作①;如果所求值大于a[m],将数组m+1~r部分继续操作①。

源码:

#include <bits/stdc++.h>

using namespace std;

int find(int a[], int l, int r, int x){

       int m = l + r >> 1;

       if(a[m] == x) return m;

       if(x < a[m]) find(a, l, m - 1, x);

       else find(a, m + 1, r, x);

}



int ffind(int a[], int l, int r, int x){

       while(l < r){

              int m = (l + r) / 2;

              if( a[m] == x){

                     return m;

              }

              if( x > a[m] )  l = m + 1;

              else r =  m - 1;

       }

}

int main(){

       int a[] = {1, 5, 6, 7, 9, 10, 12, 44};

       int x = 12;

       int l = 0;

       int r = 7;

cout << "递归: " << find(a, l, r, x) << endl;

       cout << "非递归: " << ffind(a, l, r, x);

}

 

 

2)在循环有序数组中查找指定元素x

算法描述

① 将数值分成l~m,m+1~r两部分

② 如果某一部分有序,且所求值在此范围,利用二分查找算法,否则对另一部分执行①

源码

#include <bits/stdc++.h>

using namespace std;

//递归

int Binaryseach (int a[], int l, int r, int x){

       int m  =  l + r  >> 1;

       if(x == a[m]) return m;

       if( x > a[m]) Binaryseach(a, m + 1, r, x);

       else Binaryseach(a, l, m - 1, x);

       return -1;

}

int find(int a[], int l, int r, int x){

       int m = l + r >> 1;

       if(a[l] < a[m]){  //左边有序

              if(a[l] <= x && x <= a[m]) //若x位于有序区间 ,二分查找 

                     return Binaryseach(a, l, m, x);

              else find(a, m + 1, r, x); //否则 继续查找含x的有序区间

       }

       else{

              if(a[m] <= x && x <= a[r])

                     return Binaryseach(a, m, r, x);

              else find(a, l, m - 1, x);

       }

}

//非递归

int nBinaryseach(int a[], int l, int r, int x){

       while(l < r){

              int m = l + r >> 1;

              if(a[m] == x) return m;

              if(a[m] > x) l =  m + 1;

              else r = m - 1;

       }

}



int nfind(int a[], int l, int r, int x){

      

       while(l < r){

              int m = r + l >> 1;

              if(a[m] > a[l]){

                     if(a[l] <= x && x <= a[m])

                            return nBinaryseach(a, l, m, x);

                     else  l = m + 1;

              }

              else

                     if(a[m] <= x && x <= a[r])

                            return nBinaryseach(a, m, r, x);

                     else  r = m - 1;

       }

}



int main(){

       int a[] = {9, 12, 16, 18, 20, 41, 100, 1, 4, 6};

       int l = 0;

       int r = 9;

       int x = 41;

       cout << "递归 " <<find(a, 0, 9, x) << endl;

       cout << "非递归 "<<nfind(a, 0, 9, x) << endl;

       return 0;

}

 

3)假如集合中的元素有重复, 要找到指定元素x首次出现的位置。

算法描述

 

①将数组分成l~m,m+1~r两部分

②所求数<=a[m],对l~m执行①,否则对m+1~r执行①

③当r >= l,返回l;

源码



#include<bits/stdc++.h>

using namespace std;

int Binaryseach(int a[], int l, int r, int x){

       int m = l + r >> 1;

       if(l >= r) return l;

       if(x <= a[m]) Binaryseach(a, l, m, x);

       else Binaryseach(a, m+1, r, x);          

}

int nBinaryseach(int a[], int l, int r, int x){

       while(l < r){

              int m = l + r >> 1;

              if(x <= a[m])  r = m;

              else l = m + 1;

       }

       return l;

}

int main(){

       int a[] = {1, 5, 6, 7, 9, 10, 10, 10, 12, 44};

       cout << "递归"<<Binaryseach(a, 0, 9, 10) << endl;

       cout << "非递归"<<nBinaryseach(a, 0, 9, 10) << endl;

}

 

4)在一个有序的数组里, 数据里面元素可能有重复的, 查找指定元素x所在的索引范围。

算法描述

求首位置如(3)

求尾位置:

①将数组分成l~m-1,m~r两部分

②所求数<a[m],对l~-m-1执行①,否则对m~r执行①

源码

③当r >= l,返回l;

源码

#include<bits/stdc++.h>



using namespace std;

//尾位置递归写法

int Binaryseach(int a[], int l, int r, int x){

       int m = l + r + 1>> 1;

       if(l >= r) return l;

       if(x < a[m]) Binaryseach(a, l, m - 1, x);

       else Binaryseach(a, m, r, x);

}

//首位置非递归写法

int nBinaryseach(int a[], int l, int r, int x){

       while(l < r){

              int m = l + r >> 1;

              if(x <= a[m])  r = m;

              else l = m + 1;

       }

       return l;

}



int main(){

       int a[] = {1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 6, 6, 7, 9, 11, 12};

       cout << nBinaryseach(a, 0, 15, 3) << endl;

       cout << Binaryseach(a, 0, 15, 3) << endl;

      

}

 

5)利用二分搜索的基本思想, 设计一个算法求n个数的最大值和最小值。

算法描述

①将数组分成l~mm+1~r两部分

l<r,执行① 否则返回a[l]

③比较两部分返回值 返回较小(大)值

源码

#include<bits/stdc++.h>

using namespace std;

int min(int a[], int l, int r){

       //cout << l << " ** " << r << endl;

       int m = l + ((r - l) >> 1 );

       if(l == r) return a[l];

       int m1 = min(a, l, m);

       int m2 = min(a, m + 1, r);

       //cout  << m1 << " " << m2 << endl;

       if(m1 > m2)   return m2;

       else  return m1;  

}

int max(int a[], int l, int r){

       //cout << l << " ** " << r << endl;

       int m = l + ((r - l) >> 1 );

       if(l == r) return a[l];

       int m1 = max(a, l, m);

       int m2 = max(a, m + 1, r);

       //cout  << m1 << " " << m2 << endl;

       if(m1 < m2) return m2;

       else  return m1;  

}

int main(){

       int a[] = {2, 5, 7, 6, 7, 10, 30};

       cout << min(a, 0, 6) << endl;

       cout << max(a, 0, 6);

}

 

 

任务二 合并排序

1)数组a中元素为{49, 38, 65, 67, 76, 13, 27, 28}, 用合并排序进行升序排序, 并输出排序结果。分别用递归和非递归的方式实现。

算法描述

①将数组不断分成两个集合

②分别对两个子集进行排序

③把排好序对子集合并成有序集合

源码

#include<bits/stdc++.h>

using namespace std;

void fun(int a[], int l, int m, int r){

       int i = l;

       int j = m + 1; 

       int k = 0;

       int t[10000];

       while(i <= m && j <= r){

              if(a[i] < a[j])

                     t[k++] = a[i++];

              else

                     t[k++] = a[j++];

       }

       while( i <= m) t[k++] = a[i++];

       while( j <= r) t[k++] = a[j++];

       i = 0;

       while(i < k){

              a[l++] = t[i++];

       }

}

// 递归

void sort(int a[], int l, int r){

       if(l < r){

              int m = (l + r) / 2;

              sort(a, l, m);

              sort(a, m+1, r);

              fun(a, l, m, r);

       }

}

//非递归

void fsort(int a[], int l, int r){

       int s = 1;

       while(s <= r){

              l = 0;

              while(l <= r){

                     int  p = l + s*2 - 1;//

                     if(p > r) p = r; //防止越界                  分成 【l, mid】 【mid + 1 , r】

                     int m = l + s - 1;//保证m是上次分段的断点   例如 0 1 2 3 4 5 6 7第一次断点是 0 2 4 6 第二次 1 5 

                     if(m > r) m = r;

                     fun(a, l, m, p);

                     l = p + 1;

              }

              s += s;

       }     

}

void input(int a[], int n){

       int i = 0;

       while( i < n) cout << a[i ++] << " ";

       cout << endl;

}



int main(){

       int n = 8;

       int a[] = {49,38,65,67,76,13,27,28};

       sort(a,0,n - 1);

       cout << "递归: " ;

       input(a, n);

       fsort(a,0,n - 1);

       cout << "非递归: " ;

       input(a, n); 

       return 0;

}

 

2)数组a中元素为{49, 38, 65, 67,     76, 13, 27, 28}, 用自然合并排序进行升序排序, 并输出排序结果。

算法描述

  • 找出数组的有序段,并记录下来
  • 对相邻的有序段进行合并排序,直至数组完全有序

源码

#include<bits/stdc++.h>

using namespace std;



int fun1(int a[], int n, int b[]){//找出各有序断点,并存入数组b,返回数组b元素个数

       int i = 0;

       int j = 1;

       while(i < n){

              if(a[i] > a[i+1])

                     b[j++] = i+1;

              i++;

       }

       if(b[j-1] != n)//若最后一个字符为单独一段  作此判断

              b[j++] = n;

       return j;

}

void merge(int a[], int l, int m, int r){

       int c[10] = {0};

       int i = l;

       int j = m;

       int k = 0;

       while(i < m && j < r){

              if(a[i] < a[j]) c[k++] = a[i++];

              else c[k++] = a[j++];

       }

       while(i < m) c[k++] = a[i++];

       while(j < r) c[k++] = a[j++];

       i = 0;

       while(i < k){

              a[l++] = c[i++];

       }

}

void nmergesort(int a[], int b[], int m){

      

       if(m == 1) return;

       else{

              int i = 0;

              int s = 1;

              while( i + s <= m){

                     if( m % 2 == 0)  i ++;//偶数 说明可以分成奇数段 故先不把第一段加入排序

                     while(i < m - 1){ //先做循环在做判断 所以新的循环 < m-1

                            int l = b[i];

                            i += s;

                            int c = b[i];

                            i += s;

                            int r = b[i];

                            merge(a, l, c, r);

                     }

                     s+=s;

                     i = 0;

              }

       if(m % 2 == 0){

              merge(a, 0, b[1], b[m-1]);

       }     

       }     

      

}



int main(){

       int a[]={49, 38, 65, 67, 76, 13, 27, 28};

       int b[10] = {0};

       int m = fun1(a, 8, b);

       nmergesort(a, b, m);

       int i = 0;

       while(i < 8)

              cout << a[i++] << " " ;

       return 0;

}

 

任务三 快速排序

算法描述

①选择第一个数为基准,将其放在数组中的正确位置,且保证其左边数<=(>=)基准,右边>=(<=)基准

②以基准位置对数组二分,再子集做①操作

③当所有都作为基准后,结束

源码

#include <bits/stdc++.h>

using namespace std;

int fun(int a[], int l, int r){

       int b = a[l];

       while(l < r){

              while(a[r] >= b && l < r)

                     r--;

              a[l] = a[r];

              while(a[l] <= b && l < r)

                     l++;

              a[r] = a[l];

       }

       a[r] = b;

       return r;

}

void QuickSort(int a[], int l, int r){

       if(l < r){

              int m = fun(a, l, r);

              QuickSort(a, l, m-1);

              QuickSort(a, m+1, r);  

       }

}

int  main(){

       int a[6] = {6, 7, 5, 2, 4, 8};

       QuickSort(a,0,5);

       for(int i = 0; i < 6; i++)

               cout << a[i] << " ";

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值