查找
根据给定的某个值,在查找表中确定一个其关键字(唯一的标识一个记录)等于给定值的数据元素或数据记录。

静态查找:只查找,不修改元素[线性表、顺序查找、二分查找]
动态查找:查找时,插入或者删除元素[二叉排序树]


顺序表查找
顺序查找(针对静态查找表),也叫线性查找O(n),从头开始遍历,直到最后一个记录。
优化:添加哨兵

//有哨兵的顺序查找
int foo(int *a,int n,int key)
{
    int i;
    a[0]=key;//哨兵
    i=n;
    while(a[i]!=key)
    {
        i--;
    }
    return i;
}

有序表查找

1.二分查找O(logn):

前提元素有序,原因具有n个节点的完全二叉树的深度为[logn]+1(取下)。尽管不是完全二叉树,但是同样的推导,最坏找到最后一层。

不适合动态查找。

z顺序索引_有序表查找

2.插值查找O(logn)

根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法。

二分基础上修改,low+1/2(high-low)中1/2–>(key-a[low])/(a[high]-a[low])(插值公式)

z顺序索引_线性索引查找_02

3.斐波那契查找O(logn)

黄金分割原理。

斐波那契数列

z顺序索引_有序表查找_03

//斐波那契查找
int foo(int *a,int n,int key)
{
    int low,high,mid,i,k;
    low=1;
    high=n;
    k=0;
    while(n>F[k]-1)//计算n位于斐波那契数列的位置
        k++;
    for(i=n;i<F[k]-1;i++)//将不满的数值补全
        a[i]=a[n];

    while(low<=high)
    {
        mid=low+F[k-1]-1;//计算当前分隔的下标
        if(key<a[mid])
        {
            high=mid-1;
            k=k-1;
        }else if(key>a[mid])
        {
            low=mid+1;
            k=k-2;
        }else
        {
            if(mid<=n)
                return mid;
            else
                return n;
        }
    }
    return 0;
}

斐波那契查找算法的核心:

  1. 当key=a[mid],成功;
  2. 当key< a[mid],新范围是第low个到第mid-1个,此时范围个数为F[k-1]-1个;
  3. 当key> a[mid],新范围是第m+1个到第high个,此时范围个数为F[k-2]-1个。

z顺序索引_z顺序索引_04


平均性能优于二分查找。

有序表查找的三种方法中,二分进行加法与除法运算,插值查找进行复杂的四则运算,而斐波那契查找只是进行最简单加减法运算,在海量数据的查找过程中,这种细微的差别可能会影响最终的查找效率。

三种查找的本质是分隔点的选择不同。

线性索引查找

将索引项集合组织为线性结构,即索引表。

1.稠密索引:每个记录对应一个索引项,索引项按照关键码有序,适合少量数据。

z顺序索引_顺序表查找_05


查找时,可用二分,插值等从索引表中查找关键码。

数据量大,意味着索引也得同样的数据集长度规模,不适用。2.分块索引:块内无序(二分等),块间有序(顺序查找)。每块对应一个索引,

z顺序索引_顺序表查找_06


类似图书馆藏书原理。

n个记录的数据集被平均分为m块,每个块中有t条记录。n=mxt。
Lb为查找索引表的平均查找长度。Lb=(m+1)/2,
Lw为块中查找记录的平均查找长度。Lw=(t+1)/2。

分块索引查找的平均查找长度为:

z顺序索引_大话数据结构_07

公式依赖n、t两个变量。

最好情况m=t,此时

z顺序索引_大话数据结构_08

比顺序查找O(n)快,比二分O(logn)慢。

3.倒排索引
由属性(字段、关键字)的值确定记录的位置。
这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。
由于不是有记录来确定属性值,而是有属性值来确定记录的位置,因而叫倒排索引。

优点:查找记录快
缺点:记录号不定长。

应用:Google、百度搜索引擎。


附加源码:

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */ 

int F[100]; /* 斐波那契数列 */

/* 无哨兵顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字 */
int Sequential_Search(int *a,int n,int key)
{
    int i;
    for(i=1;i<=n;i++)
    {
        if (a[i]==key)
            return i;
    }
    return 0;
}
/* 有哨兵顺序查找 */
int Sequential_Search2(int *a,int n,int key)
{
    int i;
    a[0]=key;
    i=n;
    while(a[i]!=key)
    {
        i--;
    }
    return i;
}

/* 折半查找 */
int Binary_Search(int *a,int n,int key)
{
    int low,high,mid;
    low=1;  /* 定义最低下标为记录首位 */
    high=n; /* 定义最高下标为记录末位 */
    while(low<=high)
    {
        mid=(low+high)/2;   /* 折半 */
        if (key<a[mid])     /* 若查找值比中值小 */
            high=mid-1;     /* 最高下标调整到中位下标小一位 */
        else if (key>a[mid])/* 若查找值比中值大 */
            low=mid+1;      /* 最低下标调整到中位下标大一位 */
        else
        {
            return mid;     /* 若相等则说明mid即为查找到的位置 */
        }

    }
    return 0;
}

/* 插值查找 */
int Interpolation_Search(int *a,int n,int key)
{
    int low,high,mid;
    low=1;  /* 定义最低下标为记录首位 */
    high=n; /* 定义最高下标为记录末位 */
    while(low<=high)
    {
        mid=low+ (high-low)*(key-a[low])/(a[high]-a[low]); /* 插值 */
        if (key<a[mid])     /* 若查找值比插值小 */
            high=mid-1;     /* 最高下标调整到插值下标小一位 */
        else if (key>a[mid])/* 若查找值比插值大 */
            low=mid+1;      /* 最低下标调整到插值下标大一位 */
        else
            return mid;     /* 若相等则说明mid即为查找到的位置 */
    }
    return 0;
}

/* 斐波那契查找 */
int Fibonacci_Search(int *a,int n,int key)
{
    int low,high,mid,i,k=0;
    low=1;  /* 定义最低下标为记录首位 */
    high=n; /* 定义最高下标为记录末位 */
    while(n>F[k]-1)
        k++;
    for (i=n;i<F[k]-1;i++)
        a[i]=a[n];

    while(low<=high)
    {
        mid=low+F[k-1]-1;
        if (key<a[mid])
        {
            high=mid-1;     
            k=k-1;
        }
        else if (key>a[mid])
        {
            low=mid+1;      
            k=k-2;
        }
        else
        {
            if (mid<=n)
                return mid;     /* 若相等则说明mid即为查找到的位置 */
            else 
                return n;
        }

    }
    return 0;
}


int main(void)
{    

    int a[MAXSIZE+1],i,result;
    int arr[MAXSIZE]={0,1,16,24,35,47,59,62,73,88,99};

    for(i=0;i<=MAXSIZE;i++)
    {
        a[i]=i;
    }
    result=Sequential_Search(a,MAXSIZE,MAXSIZE);
    printf("Sequential_Search:%d \n",result);
    result=Sequential_Search2(a,MAXSIZE,1);
    printf("Sequential_Search2:%d \n",result);

    result=Binary_Search(arr,10,62);
    printf("Binary_Search:%d \n",result);


    result=Interpolation_Search(arr,10,62);
    printf("Interpolation_Search:%d \n",result);


    F[0]=0;
    F[1]=1;
    for(i = 2;i < 100;i++)  
    { 
        F[i] = F[i-1] + F[i-2];  
    } 
    result=Fibonacci_Search(arr,10,62);
    printf("Fibonacci_Search:%d \n",result);

    return 0;
}

运行结果:

z顺序索引_大话数据结构_09