斐波那契查找

斐波那契查找

黃金比例又稱黃金分割,是指事物各部分間一定的數學比例關係,即將整體一分爲二,較大部分與較小部分之比等於整體與較大部分之比,其比值約爲1:0.618或1.618:1。

0.618被公認爲最具有審美意義的比例數字,這個數值的作用不僅僅體現在諸如繪畫、雕塑、音樂、建築等藝術領域,而且在管理、工程設計等方面也有着不可忽視的作用。因此被稱爲黃金分割。

大家記不記得斐波那契數列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(從第三個數開始,後邊每一個數都是前兩個數的和)。然後我們會發現,隨着斐波那契數列的遞增,前後兩個數的比值會越來越接近0.618,利用這個特性,我們就可以將黃金比例運用到查找技術中。


斐波那契查找的前提是待查找的查找表必須順序存儲並且有序。

    相對於折半查找,一般將待比較的key值與第mid=(low+high)/2位置的元素比較,比較結果分三種情況

     1)相等,mid位置的元素即爲所求

     2)>     ,low=mid+1;

     3)  <     ,high=mid-1;

   斐波那契查找與折半查找很相似,他是根據斐波那契序列的特點對有序表進行分割的。他要求開始表中記錄的個數爲某個斐波那契數小1,及n=Fk-1;

 開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1),比較結果也分爲三種

 1)相等,mid位置的元素即爲所求

 2)>   ,low=mid+1,k-=2;

說明:low=mid+1說明待查找的元素在[mid+1,hign]範圍內,k-=2 說明範圍[mid+1,high]內的元素個數爲n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1個,所以可以遞歸的應用斐波那契查找

 3)<    ,high=mid-1,k-=1;

說明:low=mid+1說明待查找的元素在[low,mid-1]範圍內,k-=1 說明範圍[low,mid-1]內的元素個數爲F(k-1)-1

 

個,所以可以遞歸 的應用斐波那契查找


// 斐波那契查找.cpp 

#include "stdafx.h"
#include <memory>
#include  <iostream>
using namespace std;

const int max_size=20;//斐波那契數組的長度

/*構造一個斐波那契數組*/ 
void Fibonacci(int * F)
{
	F[0]=0;
	F[1]=1;
	for(int i=2;i<max_size;++i)
		F[i]=F[i-1]+F[i-2];
}

/*定義斐波那契查找法*/  
int Fibonacci_Search(int *a, int n, int key)  //a爲要查找的數組,n爲要查找的數組長度,key爲要查找的關鍵字
{
  int low=0;
  int high=n-1;
  
  int F[max_size];
  Fibonacci(F);//構造一個斐波那契數組F 

  int k=0;
  while(n>F[k]-1)//計算n位於斐波那契數列的位置
	  ++k;

  int  * temp;//將數組a擴展到F[k]-1的長度
  temp=new int [F[k]-1];
  memcpy(temp,a,n*sizeof(int));

  for(int i=n;i<F[k]-1;++i)
     temp[i]=a[n-1];
  
  while(low<=high)
  {
    int mid=low+F[k-1]-1;
	if(key<temp[mid])
	{
      high=mid-1;
	  k-=1;
	}
	else if(key>temp[mid])
	{
     low=mid+1;
	 k-=2;
	}
	else
	{
       if(mid<n)
		   return mid; //若相等則說明mid即爲查找到的位置
	   else
		   return n-1; //若mid>=n則說明是擴展的數值,返回n-1
	}
  }  
  delete [] temp;
  return -1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int a[] = {0,16,24,35,47,59,62,73,88,99};
	int key=100;
	int index=Fibonacci_Search(a,sizeof(a)/sizeof(int),key);
	cout<<key<<" is located at:"<<index;
	system("PAUSE");
	return 0;
}



解析:


首先要明確:如果一個有序表的元素個數爲n,並且n正好是(某個斐波那契數 - 1),即n=F[k]-1時,才能用斐波那契查找法。 如果有序表的元素個n不等於(某個斐波那契數 - 1),即n≠F[k]-1,這時必須要將有序表的元素擴展到大於n的那個斐波那契數 - 1才行,這段代碼:for (int i = n; i < F[k] - 1; i++) { a[i] = a[high]; }便是這個作用。


下面回答第一個問題:看完上面所述應該知道①是爲什麼了吧。 查找n在斐波那契數列中的位置,爲什麼是F[k] - 1,而不是F[k],是因爲能否用斐波那契查找法是由F[k]-1決定的,而不是F[k]。如果暫時不理解,繼續看下面。


第 二個問題:a的長度其實很好估算,比如你定義了有10個元素的有序數組a[20],n=10,那麼n就位於8和13,即F[6]和F[7]之間,所以 k=7,此時數組a的元素個數要被擴充,爲:F[7] - 1 = 12個; 再如你定義了一個b[20],且b有12個元素,即n=12,那麼很好辦了,n = F[7]-1 = 12, 用不着擴充了; 又或者n=8或9或11,則它一定會被擴充到12; 再如你舉的例子,n=13,最後得出n位於13和21,即F[7]和F[8]之間,此時k=8,那麼F[8]-1 = 20,數組a就要有20個元素了。 所以,n = x(13<=x<=20)時,最後都要被擴充到20;類推,如果n=25呢,則數組a的元素個數肯定要被擴充到 34 - 1 = 33個(25位於21和34,即F[8]和F[9]之間,此時k=9,F[9]-1 = 33),所以,n = x(21<=x<=33)時,最後都要被擴充到33。也就是說,最後數組的元素個數一定是(某個斐波那契數 - 1),這就是一開始說的n與F[k]-1的關係。


第三個問題:對於二分查找,分割是從mid= (low+high)/2開始;而對於斐波那契查找,分割是從mid = low + F[k-1] - 1開始的; 通過上面知道了,數組a現在的元素個數爲F[k]-1個,即數組長爲F[k]-1,mid把數組分成了左右兩部分, 左邊的長度爲:F[k-1] - 1, 那麼右邊的長度就爲(數組長-左邊的長度-1), 即:(F[k]-1) - (F[k-1] - 1) = F[k] - F[k-1] - 1 = F[k-2] - 1。


 斐波那契查找的核心是:

 1)當key=a[mid]時,查找成功;

 2)當keya[mid]時,新的查找範圍是第mid+1個到第high個,此時範圍個數爲F[k-2] - 1個,即數組右邊的長度,所以要在[F[k - 2] - 1,high]範圍內查找。

發佈了25 篇原創文章 · 獲贊 18 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章