面试笔试算法系列之分治法

来源:互联网 发布:王吴悠是什么梗 知乎 编辑:程序博客网 时间:2024/05/21 17:14

面试笔试算法系列之分治法

分治法:顾名思义乃是分而治之的意思,将一个大规模的问题分成若干个小规模的子问题。其中每个子问题是相对独立的,小规模情况下容易解。

问题举例:

1.快速排序

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

  • 面试中经常会要求写出快速排序的代码,一段简洁代码如下:

    void Qsort(int a[], int low, int high){  if(low >= high)  {      return;  }  int first = low;  int last = high;  int key = a[first];/*用字表的第一个记录作为枢轴*/  while(first < last)  {      while(first < last && a[last] >= key)      {          --last;      }      a[first] = a[last];/*将比第一个小的移到低端*/      while(first < last && a[first] <= key)      {          ++first;      }      a[last] = a[first];    /*将比第一个大的移到高端*/  }  a[first] = key;/*枢轴记录到位*/  Qsort(a, low, first-1);  Qsort(a, first+1, high);}

    我们举例 57, 68, 59, 52, 72, 28, 96, 33, 24,上述代码的过程主要是设置一个first指针和last指针,分别指向比key小的值和比key大的值,上述代码的过程简洁,但是代码细节过强。

  • 使用Partition函数进行分治快排

    int Partition(int* data,int length,int start,int end){if(data==NULL||length<0||start<0||end>length-1)    exit(0);//数组中随机选取一个数字,将数组分为两组,左边的比该数字小,右边的比该数字大int index = Random(start,end);//放到最后的位置,以便和所有的数进行比较 Swap(&data[end],&data[index]);//定义一个small,指向当前比选中数(现在的位置是data[end])小的数int small = start-1; for(int index = start;index < end;index++){    if(data[index]<data[end]){        //找到一个比选中数小的数        small++;        //判断当前位置index和small所指的位置是否相等        if(index!=small){            Swap(&data[index],&data[small]);        }     } } //定位到新的位置,把选中的数放回去 small++;Swap(&data[small],&data[end]); return small;}

    这个使用Partition函数的快速排序过程如下图所示,

    Markdown

2.找出数组中出现次数大于一半的数字

  • 该问题可以使用一个Partition分治函数去解决,寻找对应中间位置的数字,即为所需数字,源码如下

    #include <iostream>#include <stdlib.h>#include <time.h> using namespace std;void Swap(int *a,int *b){int temp=*a;*a = *b;*b=temp;} int Random(int start,int end){srand((unsigned)time(NULL)); return start+(int)(rand()%(end-start+1));}int Partition(int* data,int length,int start,int end){if(data==NULL||length<0||start<0||end>length-1)    exit(0);//数组中随机选取一个数字,将数组分为两组,左边的比该数字小,右边的比该数字大int index = Random(start,end);//放到最后的位置,以便和所有的数进行比较 Swap(&data[end],&data[index]);//定义一个small,指向当前比选中数(现在的位置是data[end])小的数int small = start-1; for(int index = start;index < end;index++){    if(data[index]<data[end]){        //找到一个比选中数小的数        small++;        //判断当前位置index和small所指的位置是否相等        if(index!=small){            Swap(&data[index],&data[small]);        }     } } //定位到新的位置,把选中的数放回去 small++;Swap(&data[small],&data[end]); return small;}void QuickSort(int data[],int length,int start,int end ){    if(start==end)        return;int index = Partition(data,length,start,end);   if(index>start){    QuickSort(data,length,start,index-1);}if(index<end){    QuickSort(data,length,index+1,end);}} //寻找数组中出现次数超过一半的数字int findMoreThanHalf(int* data,int length,int start,int end){int middle = length/2;int index = Partition(data,length,start,end);while(index!=middle){    if(index>middle){        end = index-1;        index = Partition(data,length,start,end);    }else{        start = index+1;        index = Partition(data,length,start,end);                           }}return data[index];}int main(){srand((unsigned)(time(NULL)));int length = Random(1,20);int data[length];  int start =1;int end =1000;for(int i=0;i<length;i++){    data[i]=start+(int)(rand()%(end-start+1));}  int data[10] ={12,34,54,54,67,54,2,54,54,54};  int length=10;for(int i=0;i<length;i++){    cout<<data[i]<<" ";}printf("\n");cout<<"中位数是"<<findMoreThanHalf(data,length,0,length-1)<<endl; QuickSort(data,length,0,length-1);for(int i=0;i<length;i++){    cout<<data[i]<<" ";}return 0;} 
0 0
原创粉丝点击