9.5 插补查找

插补查找(Interpolation Searching): 类似与折半查找,只不过和欲查找数据比较的不是中间项,而是以内插法按照比例所选出来的一项。

如果low为数据的左边边界(下限),high为数据的右边边界(上限),keyValue为欲查找值,该值位于low和high之间,data[low]和data[high]分别为数据的左右边界值,那么,如果设middle为与欲查找值做比较的数据位置。那么,有公式为:


然后data[middle] 与keyValue相比较,循环确定low和high及middle的值查到该值或者low

的值大于high(表明未查到)。具体情况和折半查找相似。

附注:

插补查找法对于平均分布的数据效率很高,其时间复杂度为O(log2log2n),比折半查找法还要好,不过对于不平均分布的数据效率却不好,其最坏状况时的时间复杂度可能达到O(n)

1、以下是简单的查补查找的操作(未优化情况下),及在数据不均匀分布情况下,效率不高:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/***********************************************************/
// 程序名称:InterpolationSearch.cpp
// 程序目的:设计一个插补查找的程序
// 程序来源:数据结构与算法分析(C语言版) P-293
// 日期: 2013-8-30 8:11:56 JohnnyHu改进
/***********************************************************/

#include <stdio.h>
#include <stdlib.h>

#define  MAX  20
#define  NotFound  - 1
typedef  int ElementType;

ElementType data[MAX] = {    1214192225,
                             3239404547,
                             4853545960,
                             6869687077 };  // 数据数组

int InterpolationSearch( const ElementType data[], ElementType keyValue);

int main( void)
{
     int keyValue;
    printf( "请输入您要查找的(int)值,输入0退出: ");
     while(scanf( "%d", &keyValue))
    {
         if ( 0 == keyValue)
             break;

         int index = InterpolationSearch(data, keyValue);
         if (NotFound != index)
            printf( "您要查找的值是: data[%d] = %d \n", index, data[index]);
         else
            printf( "没找到!\n");

        printf( "请输入您要查找的(int)值,输入0退出: ");
    }

     return  0;
}

/************************************************************************/
// 插补查找
/************************************************************************/

int InterpolationSearch( const ElementType data[], ElementType keyValue)
{
     int low, high, middle;

    low =  0;
    high = MAX -  1;
    middle = low + (keyValue - data[low]) * (high - low)
            / (data[high] - data[low]);

     if (middle < low)
        middle = low;
     if (middle > high)
        middle = high;

     while (low <= high)
    {
         if (keyValue < data[middle])
            high = middle -  1;   // 查找前半段
         else  if (keyValue > data[middle])
            low = middle +  1;    // 查找后半段
         else  if (keyValue == data[middle])
             return middle;       // 找到数据

         if (low < high)
            middle = low + (keyValue - data[low]) * (high - low)
            / (data[high] - data[low]);

         if (middle < low)
            middle = low;
         if (middle > high)
            middle = high;
    }

     return NotFound;
        
}

2、对应不均匀分布的数据,如果采用插补查找法,不但无法增快查找速度,反而让最差状况的时间复杂度达到O(n),接近线性查找法。那么以下是对函数的改进,叫做加强型插补查找法(Robust Interpolation Searching)

改良后的插补查找法:

9.5 插补查找_第1张图片

比较num1、num2、num3那么middle则取这三数之间的中间值

下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/************************************************************************/
// 找出加强型插补查找的中间值
/************************************************************************/

int Findrobust( const ElementType data[], ElementType keyValue,  int low,  int high)
{
     int gap;     // 差值
     int num1;    // 数值1
     int num2, num3;

    gap = ceil(sqrt(high - low +  1. 0));      // ceil上取整,floor下取整
    num1 = low + gap;
    num2 = high - gap;
    num3 = low + (keyValue - data[low]) * (high - low) / (data[high] - data[low]);

     if (num1 > num2)
    {
         if (num2 > num3)
             return num2;     // num1 >= num2 >= num3
         else  if (num1 >= num3)
             return num3;     // num1 >= num3 >= num2
         else 
             return num1;     // num3 >= num3 >= num2
    }
     else  if (num2 >= num1)
    {
         if (num1 >= num3)
             return num1;     // num2 >= num1 >= num3
         else  if (num3 >= num1)
             return num3;     // num2 >= num3 >= num1
         else
             return num2;     // num3 >= num2 >= num1
    }

     return  0;
}


/************************************************************************/
// 插补查找
/************************************************************************/

int InterpolationSearch( const ElementType data[], ElementType keyValue)
{
     int low, high, middle;

    low =  0;
    high = MAX -  1;
    middle = Findrobust(data, keyValue, low, high);

     if (middle < low)
        middle = low;
     if (middle > high)
        middle = high;

     while (low <= high)
    {
         if (keyValue < data[middle])
            high = middle -  1;   // 查找前半段
         else  if (keyValue > data[middle])
            low = middle +  1;    // 查找后半段
         else  if (keyValue == data[middle])
             return middle;       // 找到数据

         if (low < high)
            middle = low + (keyValue - data[low]) * (high - low)
            / (data[high] - data[low]);

         if (middle < low)
            middle = low;
         if (middle > high)
            middle = high;
    }

     return NotFound;

}

从中可以看出,只是增加了利用FindRobust来求middle的值,其他部分没变!!!

加强型插补查找法,对于均匀分布的数据,其时间复杂度为O(loglogn),对于非均匀分布的数据,其时间复杂度为O((log)^2),虽然没有折半查找好,但对于改善原来的插补查找法最差情况时间复杂度O(n)却有明显的差别。

输出结果:

9.5 插补查找_第2张图片



你可能感兴趣的:(折半查找,插补查找)