• 二分查找的二分法和黄金分割点比较


    笔记和代码的思路来源:

    好大学慕课浙江大学陈越、何钦铭的《数据结构》

    讨论3.1 黄金分割查找?

    老师参与

    在二分查找中,我们是取mid等于left和right的中间值,即用等分的方法进行查找。

    那为什么一定要等分呐?能不能进行“黄金分割”?也就是mid=left+0.618(right-left),当然mid要取整数。如果这样查找,时间复杂性是多少?也许你还可以编程做个试验,比较一下二分法和“黄金分割”法的执行效率。

     
    证明来自好白的小白。

    二分法每次能有100%的概率能只剩50%的数据,每次剩下的期望为50%,即每次除以2。所以时间复杂度是

    而黄金分割的话每次都有0.618的概率剩0.618,0.382的概率剩0.382,每次剩下的期望为0.528,即每次除以1.894。所以时间复杂度是

    虽然两者都是O(logN)类,但是系数不同,黄金分割法所需时间约为二分法的1.085倍(此处没考虑取整……)。

    假设分割点距左侧的距离除以全长等于p,那么每次剩下的期望为个全长。要让这个期望最小,我们知道p要等于1-p。所以p=0.5。所以二分法分在正中。

     
    下面是是自己的代码和测试过程:
     
      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<time.h>
      4 #include<math.h>
      5 
      6 #define MAXSIZE 1000000
      7 
      8 typedef int dataType;
      9 
     10 typedef struct node{
     11     dataType data[MAXSIZE];
     12     int length;
     13 }lis,*pList;
     14 
     15 
     16 pList createEmptyList(){
     17     pList list = (pList)malloc(sizeof(lis));
     18     if(list){
     19         list->length=-1;
     20     }
     21     return list;
     22 }
     23 
     24 int isFull(pList list){
     25     return (list->length==MAXSIZE-1);
     26 }
     27 
     28 int isEmpty(pList list){
     29     return (list->length==-1);
     30 }
     31 
     32 void insert(pList list,dataType element){
     33     if(isFull(list)){
     34         printf("the list has full");
     35         return;
     36     }
     37     list->data[++(list->length)]=element;
     38 
     39 }
     40 
     41 dataType findIndex(pList list,int index){
     42     if(isEmpty(list)){
     43         printf("the list is empty");
     44         return;
     45     }
     46     return list->data[index];
     47 }
     48 
     49 void toString(pList list){
     50     int length=0;
     51     printf("
    toString:");
     52     while(length<=list->length){
     53         printf("%d ",list->data[length]);
     54         length++;
     55     }
     56 }
     57 
     58 
     59 /*
     60 不使用哨兵是算法就会导致每次循环进行一次i<=list->length的判断,
     61 为了演示方便,我们这里的数组角标从1开始,0角标存放的是数组的长度+1
     62 */
     63 int orderSearch(pList list,int element){
     64     int i;
     65     for(i=0;i<=list->length && list->data[i]!=element;i++);
     66     if(i>list->length){
     67         return -1;
     68     }else{
     69         return i;
     70     }
     71 }
     72 
     73 /*
     74 使用顺序查找,使用哨兵算法,
     75 如果使用哨兵算法,那么数组的第一个元素就只能存放数组的长度
     76 数组的真正的角标是从1开始的。0号角标存放的需要查找的元素element,
     77 当循环退出是,要么是找到了,返回找到元素的角标i
     78 要么是i=0;没找到
     79 */
     80 int orderSearch2(pList list,int element){
     81     int i;
     82     list->data[0]=element;
     83     for(i=list->length;list->data[i]!=element;i--);
     84     return i;//0表示没有找到
     85 }
     86 
     87 /*二分查找,去终点作为分割点*/
     88 int binarySearch(pList list,int element){
     89     int left=1;
     90     int right=list->length;
     91     while(left<=right){
     92         int mid=(right+left)/2;
     93         if(element>list->data[mid]){
     94             left=mid+1;
     95         }else if(element<list->data[mid]){
     96             right = mid - 1;
     97         }else{
     98             return mid;
     99         }
    100     }
    101     return -1;//没找到,返回-1
    102 }
    103 
    104 /*
    105 二分查找,取黄金分割点作为中点
    106 */
    107 int binarySearch2(pList list,int element){
    108     int left=1;
    109     int right=list->length;
    110     while(left<=right){
    111         int mid=left+0.618*(right-left);
    112         if(element>list->data[mid]){
    113             left=mid+1;
    114         }else if(element<list->data[mid]){
    115             right = mid - 1;
    116         }else{
    117             return mid;
    118         }
    119     }
    120     return -1;//没找到,返回-1
    121 }
    122 
    123 
    124 void main(){
    125     int i=0,j=0;
    126     clock_t start,end;
    127     double duration;//used to stored top - end
    128 
    129     int count =10;
    130     pList list = createEmptyList();
    131 
    132     insert(list,MAXSIZE);
    133     for(i=1;i<MAXSIZE;i++){
    134         insert(list,i);
    135     }
    136 
    137 
    138 
    139     start=clock();
    140     start=clock();
    141     for(j=0;j<count;j++){
    142         for(i=0;i<MAXSIZE;i++){
    143             binarySearch(list,i);//使用中点分割
    144         }
    145     }
    146     end=clock();
    147     duration=((double)(end-start))/CLK_TCK/MAXSIZE/count;
    148     printf("use middle as the split point:%f
    ",duration);
    149 
    150 
    151     start=clock();
    152     for(j=0;j<count;j++){
    153         for(i=0;i<MAXSIZE;i++){
    154             binarySearch2(list,i);//使用黄金分割点分割
    155         }
    156     }
    157     end=clock();
    158     duration=((double)(end-start))/CLK_TCK/MAXSIZE/count;
    159     printf("use huangJinFenGeDian as the split point:%f
    ",duration);
    160 
    161 
    162     //toString(list);
    163 
    164 /*
    165     insert(list,10);
    166     for(i=1;i<=10;i++){
    167         insert(list,i);
    168     }
    169     printf("%d ",orderSearch2(list,7));
    170     printf("%d ",orderSearch2(list,11));
    171     printf("%d ",binarySearch(list,9));
    172     printf("%d ",binarySearch(list,11));
    173     toString(list);
    174 */
    175 }
    View Code

    进行累计计时就求平均的思想,但是当count=100时,PC机运算时间太慢了,就没有测试。

    下面是count=10的测试结果,发现基本上查不了多少。但是上面的逻辑证明更加准确。

     
     
  • 相关阅读:
    wampserver域名访问报错
    提升linux文件夹权限
    linux压缩
    服务器重启记录
    修改mysql数据库密码
    电脑没声音解决
    删除任务管理其中的多余的启动项
    资源占用无法删除解决方案
    删除资源管理器中左边菜单的onedrive
    13. 导航
  • 原文地址:https://www.cnblogs.com/yghjava/p/6672464.html
Copyright © 2020-2023  润新知