有序序列查找-斐波那契查找(Fibonacci Search)

斐波那契查找是一种针对有序数组的搜索算法,它通过斐波那契数列确定分割点,避免了除法运算,适用于大型数据集。文章介绍了算法原理,包括数组的非对称分割和如何找到合适的斐波那契数作为分割点,以及提供了一个C语言的代码实现示例。
摘要由CSDN通过智能技术生成

有序序列查找-斐波那契查找(Fibonacci Search)

  1. 前言

如果数组为有序表或有序数列,查找函数可以采用斐波那契查找实现。斐波那契查找与折半查找(二分查找)的最大区别是,斐波那契查找函数对有序表进行分对称分割,而折半查找则是对有序表进行对对称分割;另外斐波那契查找的位置确定仅涉及到加减运损,而折半查找则涉及到除法运算;研究表明斐波那契搜索在后续步骤中检查相对接近的元素,因此,当输入数组很大,无法放入 CPU 缓存甚至 RAM 时,斐波那契搜索会派上用场。

斐波那契查找本质上是对有序表进行分而治之,先对原来数组进行分裂处理,进而找到待查找元素所属的子区间,后面反复进行处理,直至找到查询的对象或查询失败。

  1. 算法分析

算法的关键是找到合适的分割点,这些分割点隶属于某个斐波那契数,所以问题转化为,每次分治前,需要寻找到合适的斐波那契数字。为了查询方便,我们可以引入Fib数组,这个数组中储存的最大斐波那契数字恰好大于数组中元素的个数,也就是Fib[u]>n,其中u为的最小的下标值,定义u为查询问题中Fib数组的上界(upper bound)。

先看一个具体的例子,给定有序数列,数列中包含15个元素,并且元素为有序递增排列。

在这里插入图片描述

在此条件下,我们就要寻找斐波那契数字,斐波那契的值需要大于15的最小值,显而易见21为我们需要搜索的具体值,上界下标的值(upper bound)u等于7。

在这里插入图片描述

假定要寻找目标数字等于88,第一个分割点位置为low+F[u-1],那么其左边元素个数不超过F[u-2],右半部分元素数量不超过F[u-3],由于右半部分的分割点的值可能大于最高点位置,所以mid在这里就需要取low+F[u-1]-1和high之间的最小值,确保mid值不越界。

在这里插入图片描述

  1. 搜索过程

假定搜索目标为88,那么第一次分割,选择左半部分,继续搜索,

在这里插入图片描述

第二次分割后,88属于右半部分,

在这里插入图片描述

第三次分割后,88属于左半部分,

在这里插入图片描述

此时mid=10,所以查询结束。

  1. 代码实现

代码的数据结构参考清华大学严蔚敏的《数据结构(C语言版)》的基本数据类型,利用这些数据类型构建查询表(Search Table),构造数据类型过程中利用到文件指针的相关知识,在此不再赘述。

代码分为三个关键函数,第一部分是寻找斐波那契的下标的上界值和构建斐波那契数组:

第一部分为头文件定义

/**
 * @file Fib_search.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-04-08
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef FIB_SEARCH_H
#define FIB_SEARCH_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../00_introduction/Status.h"

#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))

#define MAX_LEN 20

typedef int   KeyType;
typedef char* Record;


typedef struct  SElemType
{
    KeyType key;
    Record  value;
}SElemType;

typedef struct SSTable
{
    SElemType *elem;
    int        len;
} SSTable;

void CreateTable(FILE *fp, SSTable *st);



int fib_search_iteration(SSTable st, KeyType key,int u, int *fib);


int find_upper_bound(SSTable st,int **fib);


int min(int a, int b);


#endif

第二部分关键函数的实现

/**
 * @file Fib_search.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-04-08
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef FIB_SEARCH_C
#define FIB_SEARCH_C
#include "Fib_search.h"

void CreateTable(FILE *fp, SSTable *st)
{
    int n;
    char str[MAX_LEN];
    int i;


    n=0;
    // 当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
    while(fgets(str,MAX_LEN,fp)!=NULL)
    {
        n++;
    }

    fseek(fp,0,SEEK_SET);

    st->len=n;
    st->elem=(SElemType *)malloc(sizeof(SElemType)*(n+1));

    for(i=1;i<=n;i++)
    {
        st->elem[i].value=(Record)malloc(sizeof(char)*MAX_LEN);
        memset(st->elem[i].value,0,sizeof(char)*MAX_LEN);
        fscanf(fp,"%d %s",&(st->elem[i].key),st->elem[i].value);
    }

    return;    
}

int find_upper_bound(SSTable st, int **fib)
{
    int n;
    int u;
    int i;
    int max_num=10;
    int dp[max_num];

    dp[0]=1;
    dp[1]=1;
  
    n=st.len;

    for(i=2;i<max_num;i++)
    {
        dp[i]=dp[i-1]+dp[i-2];

        if(dp[i]>n)
        {
            break;
        }
    }

    *fib=(int *)malloc(sizeof(int)*(i+1));

    memcpy(*fib,dp,sizeof(int)*(i+1));

    return i;
}

int fib_search_iteration(SSTable st, KeyType key, int u, int *fib)
{
    int low;
    int high;
    int mid;
    int index;

    low=1;
 
    high=st.len;
    index=u-1;

    while(low<=high && index>=0)
    {
        mid=min(low+fib[index]-1,high);

        // 1、1、2、3、5、8、13、21、34
        if(EQ(key,st.elem[mid].key))
        {
            return mid;
        }
        else if (LT(key, st.elem[mid].key))
        {
            high=mid-1;
            index=index-1;
        
        }
        else
        {
            low=mid+1;
            index=index-2;     
        }
     
    }

    if (low==high && EQ(key, st.elem[low].key) && index <0)
    {
        return low;
    }
    else
    {
        return 0;
    }
}

int min(int a, int b)
{
    return (a<b?a:b);
}

#endif

第三部分为测试函数

/**
 * @file Fib_search_main.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-04-08
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef FIB_SEARCH_MAIN_C
#define FIB_SEARCH_MAIN_C
#include "Fib_search.c"

int main(void)
{
    FILE *fp;
    KeyType key_1=88;
    KeyType key_2 = 85;
    SSTable st;
    int u;
    int index_1;
    int index_2;
    int *fib;

    fp=fopen("data.txt","r");
    CreateTable(fp,&st);

    // 1,1,2,3,5,8,13,21,34
    u=find_upper_bound(st,&fib);

    index_1=fib_search_iteration(st,key_1,u,fib);
    //index_2=fib_search_recursion(1,st.len,st,key_1,u,fib);
    

    printf("The index is %d and %d\n",index_1,index_2);
    
    getchar();
    return EXIT_SUCCESS;
}


#endif

data.txt文件

5 fox
13 the
19 jump
21 out
37 box
56 it
64 looks
75 very
80 sad
88 do
92 feel
157 good
200 bad
235 june
270 nice
  1. 小结

通过本问题的分析,对斐波那契搜索方法有了更进一步的认识,同时理解斐波那契搜索为非对称搜索,在过程中可能产生越界,处理越界称为本搜索问题的关键。

参考资料:

  1. Fibonacci Search - GeeksforGeeks
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值