1. 程式人生 > >查找算法1-Fibonacci查找

查找算法1-Fibonacci查找

pan 指定 spa uek pgm ace 我們 ev3 縮小

斐波那契查找是一種在有序表中高效查找指定元素的算法,比折半查找要復雜一些,主要復雜在要多做不少準備工作。下面看它的工作流程:

1.計算並保存一個斐波那契序列的數組,方便以後取值。數組名記為f,例如f[1]=1,f[2]=1,f[3]=2,f[4]=3,f[5]=5,f[6]=8,f[7]=13,f[8]=21

2.把有序數組的長度擴充到a.length=f[k]-1,k是滿足條件的最小值,比如數組長度為13,那麽就把它長度擴充到f[8]-1=20,所有在末尾添加的擴充元素都是原數組最後一個元素的復制品

3.找到mid元素,不斷進行二分比較,直到找到目標元素為止,這一步的做法與折半查找一模一樣,僅僅是計算mid的公式從(low+high)/2改為low+(f[k-1]-1)。

斐波那契查找的理解難點就一個:為什麽需要把數組長度擴充到f[k]-1而不是f[k]或者 f[k+1]?這是為了能正確遞歸計算mid值,看下圖可發現 f[k]-1 = (f[k-1] + f[k-2]) - 1 = (f[k-1]-1) + 1 + (f[k-2]-1),中間的1就是我們二分的錨點mid,如果目標在左區,數組長度就縮到(f[k-1]-1),如果在右區,數組長度就縮到 (f[k-2]-1),否則就等於mid完成查找。而(f[k-1]-1)又能拆成(f[k-2]-1)+1+(f[k-3]-1),這樣遞歸分割下去就 能不斷的縮小區間直至找到目標。

技術分享

#include <stdio.h>
#define
LEN 9 #define MAXSIZE 100 int F[50];//fibonacci數列 //構造fibonacci數列 void FibonacciArray(int * a){ int i; a[0]=1; a[1]=1; for(i=2; i<50; i++){ a[i]=a[i-1]+a[i-2]; } } //進行fibonacci查找,返回0即查找失敗,否則返回找到的下標 int FibonacciSearch(int * a,int n,int key){ int k=0,i; int mid,low=1,high=n;
while(n>F[k]-1) k++;//確定初始k值 for(i=n+1; i<=F[k]-1; i++ ){ a[i]=a[n]; //補全a[n+1]到a[F[k]-1],使之都==a[n] } //開始查找 while(low<=high){//註意 mid=low+F[k-1]-1; if(a[mid]>key){//如果中間值比要查找的值大 high=mid-1; k=k-1; }else if(a[mid]<key){ low=mid+1; k=k-2; }else{//a[mid]==key if(mid<=n) return mid; else if(mid>n)//說明找到的下標在原來填補的位置上,是和a[n]相同的,所以返回n return n; } } return 0;//返回0,即key不在數組a中 } int main(){ int a[LEN+1]={0,8,23,45,78,89,25,68,47,59};//設首位為哨兵 int arr[MAXSIZE]={0};//設一個足夠大的數組,代入函數計算 for(int i=0; i<LEN+1; i++){ arr[i]=a[i]; } int result; int key=59; FibonacciArray(F);//返回[1,1,2,3,5,...] //printf("%d",F[7]); result=FibonacciSearch(arr,LEN,key); if(result!=0){ printf("%d存在數組a中,等於a[%d]\n",key,result); }else printf("數組a中不存在%d\n",key); return 0; }

結果:

技術分享

之前寫的時候返了一個錯誤,while(low<=high)小於等於寫成了<;

參考:

[1]大話數據結構,p.303-304

[2]http://blog.csdn.net/lzdidiv/article/details/59784694

查找算法1-Fibonacci查找