有序(循环)数组查找元素-二分查找法

来源:互联网 发布:python基础教程 mobi 编辑:程序博客网 时间:2024/04/25 23:36

1.我们将一个有序数组(n个元素)从i(号位置)之前放到n位置之后形成的数组为有序循环数组。

2.数组 1 2 4 5 6 7 8

   的有序循环数组有

  1 2 4 5 6 7 8 (元数组是位置0处的有序循环数组).

  2 4 5 6 7 8 1 

  4 5 6 7 8 1 2

  5 6 7 8 1 2 4

  6 7 8 1 2 4 5 

  7 8 1 2 4 5 6

  8 1 2 4 5 6 7

3.我们要在有序循环数组中找到一个元素出现的位置(此处假设每个元素出现次数小于等于一)。

a.顺序差 O(n) 

b.(二次)二分查找O(2logn) ~ O(logn)。

此处先说明一下二分查找.

若数组有序那么我们取首个位置为l,最后位置为r,中间位置为m=(l+r) /2,要找的元素为val 

l<=r时

若A [ m] ==val则找到.

若A[m]>val 则在左边找l=m-1;

若A[m]<val则在右边找r=m+1;

重复过程直到找到.

有下列.

在0 2 3 4 7 8 10 11 70 100 101 中查找 7 ,则会在第三步找到.

若查找5则会在第四步找不到退出。


给出代码:

#include <stdio.h>#define SIZE 100int binary_find(int number[],int l,int r,int val){       int lft = l, rit = r ,mid = lft;    while( lft <= rit ){              mid = (rit + lft)/2;              if( number[mid] == val){                  return mid;              }else if(number[mid] > val){                      rit = mid - 1;                    }else{                      lft = mid + 1;              }    }    return -1;}int main(){    int number[SIZE] = {5,8,10,11};    int i,count=4,val=11,mid=-1;    mid = binary_find(number,0,count-1,,val);    if(mid!=-1){               printf("find :%d at pos:%d!\n",number[mid],mid);    }else{               printf("nomber %d !\n",val);    }    getchar();     return 0;} 

现在来考虑问题在循环有序中的数组中查找元素出现的位置。

假设你知道那个边界点位置为i(i和前面元素有序并且大于每一个i后面的有序序列中的元素元素。

10 11 70 100 101 0 2 3 4 7 8 此处的边界点i为4(从零计算下标)

那么可以将0-4挪到11~15位置,在使用二分查找从(5,15)查找即可。

那么就有新的问题如何找到原序列中的边界点。

1.若果原序列有序,或者只有一个元素直接二分查找。

2.否则为循环多元素的数组,那么需要找分界点.

分界点的特点就在于.

i是分界点下表 a[i] > a[i+1]

若a[pos] < a[r] 则分界点在pos左边(r右边界下标)

若a[pos] > a[l] 则分界点在pos右边(l左边界下标)

相当于换了一次二分查找的条件来查找分界点位置.

找到之后就是来映射分界点左边的元素到分界点右边元素之后。如图


若当前位置为pos,原来右下标为r-1 pos >= r 是真实位置是pos - (r - l - pos);

否则就是本身。

给出代码:

#include <stdio.h>#define SIZE 100int main(){    int number[SIZE] = {5,6,7,8};    int i,count=4,val=6;     int lft = 0, rit = count - 1 ,mid = lft,pos = -1,key_pos;    for(i=0;i < count;i++){              printf("%d ",number[i]);    }    if( number[0] <= number[count - 1] ){ //原本为有序串,直接二分查找                while( lft <= rit ){                     mid = (rit + lft)/2;                     if( number[mid] == val){                         printf("find :%d at pos:%d\n",number[mid],mid);                         break;                     }else if(number[mid] > val){                           rit = mid - 1;                           }else{                           lft = mid + 1;                     }              }              if(lft>rit)               printf("no meber :%d\n",val);    }else{                                   //查找分界点               while( lft <= rit ){                     mid = (rit + lft)/2;                     if( number[mid] >= number[mid + 1] ){                         break;                     }else if(number[mid] <= number[count - 1 ]){                           rit = mid - 1;                           }else{                           lft = mid + 1;                     }              }              lft = mid + 1,rit = count + mid ,key_pos = mid;               while( lft <= rit ){             //进行查找元素                      mid = (rit + lft)/2;                     int pos = mid >= count ? mid -(count - key_pos + 1) : mid;                     if( number[pos] == val){                         printf("find :%d at pos:%d\n",number[pos],pos);                         break;                     }else if(number[pos] > val){                           rit = mid - 1;                           }else{                           lft = mid + 1;                     }              }              if(lft>rit)              printf("no meber :%d\n",val);    }    return 0;} 


  

0 0