实现分块查找的算法

/**
*    实验题目:
*        实现分块查找的算法
*    实验目的:
*        领会分块查找的过程和算法设计
*    实验内容:
*        设计程序,输出在顺序表(8, 14, 6, 9, 10, 22, 34, 18, 19, 31, 40, 38,
*    54, 66, 46, 71, 78, 68, 80, 85, 100, 94, 88, 96, 87)中采用分块查找方法
*    查找(每块的块长为5,共有5块)关键字46的过程
*
*/

#include <stdio.h>

#define MAX_LEN (100)

typedef int key_type;                // 定义关键字类型为int
typedef char info_type;

typedef struct
{
    key_type key;                    // 关键字项
    info_type data;                  // 其他数据项,类型为InfoType
}rec_type;                           // 声明查找顺序表元素类型

#define MAX_INDEX (20)                      // 定义索引表的最大长度

typedef struct
{
    key_type key;                           // key_type为关键字的类型
    int link;                               // 指向分块的起始下标
}idx_type;                                  // 索引表元素类型

/*-------------------创建顺序表---------------------*/
void create_list(rec_type records[], key_type keys[], int n)
{
    int i;

    for(i = 0; i < n; i++)                  // records[0...n - 1]存放排序记录
        records[i].key = keys[i];
}

/*-------------------输出顺序表---------------------*/
void disp_list(rec_type records[], int n)
{
    int i;

    for(i = 0; i < n; i++)
        printf("%d ", records[i].key);
    printf("\n");
}

/*------------------------------分块查找算法---------------------------*/
/**
*   采用分块查找方法在顺序表records(含有n个元素)中查找关键字为key的记录位置。
*   其中records[0...n - 1]为含n个元素的主数据表,共分b个块,idxs[0...b - 1]
*   为对应的索引表。
*/
static int idx_search(idx_type idxs[], int b, rec_type records[], int n, key_type key)
{
    int s = (n + b - 1) / b;    // s为每块的元素个数,应为n/b取上界
    int count1 = 0;
    int count2 = 0;
    int low = 0, mid, high = b - 1;
    int i;

    printf("(1)在索引表中折半查找\n");
    while(low <= high) // 在索引表中进行折半查找,找到的位置为high + 1
    {
        mid = (low + high) / 2;
        printf("  第%d次比较:在[%d,%d]中比较元素records[%d]:%d\n", count1 + 1, low, high, mid, records[mid].key);
        if(idxs[mid].key >= key)
            high = mid - 1;
        else
            low = mid + 1;
        count1++;   // count1累计在索引表中的位置
    }
    printf("比较%d次,在第%d块中查找元素%d\n", count1, low, key);
    // 应在索引表的high + 1块中,再在主数据表中进行顺序查找
    i = idxs[high + 1].link;    // 找到对应的块
    printf("(2)在对应块中顺序查找:\n");
    while(i <= idxs[high + 1].link + s - 1)
    {
        printf("%d ", records[i].key);
        count2++;       // count2累计在顺序表对应块中的比较次数
        if(records[i].key == key)
            break;
        i++;
    }
    printf("比较%d次,在顺序表中查找元素%d\n", count2, key);
    if(i <= idxs[high + 1].link + s - 1)
        return i + 1; // 查找成功,返回该元素的逻辑序号
    else
        return 0;   // 查找失败,返回0
}

int main(void)
{
    // 定义结构体数组
    rec_type records[MAX_LEN];
    idx_type ids[MAX_INDEX];
    int i;
    int n = 25; // 顺序表的长度
    int a[] = {
                8, 14, 6, 9, 10,
                22, 34, 18, 19, 31,
                40, 38, 54, 66, 46,
                71, 78, 68, 80, 85,
                100, 94, 88, 96, 87
              };
    create_list(records, a, n); // 建立顺序表
    /*--------------------建立索引表----------------------*/
    ids[0].key = 14;        // key分块中取最大的
    ids[0].link = 0;        // link分块的起始下标

    ids[1].key = 34;
    ids[1].link = 5;

    ids[2].key = 66;
    ids[2].link = 10;

    ids[3].key = 85;
    ids[3].link = 15;

    ids[4].key = 100;
    ids[4].link = 20;

    printf("关键字序列:\n");
    for(i = 0; i < n; i++)
    {
        printf("%4d", records[i].key);
        if(((i + 1) % 5 )== 0)
            printf("  ");

        if(((i + 1) % 10 )== 0)
            printf("\n");
    }
    printf("\n");
    key_type key = 46;
    printf("查找%d的比较过程如下:\n", key);
    i = idx_search(ids, 5, records, 25, key);
    if(i != 0)
        printf("元素%d的位置是%d\n", key, i);
    else
        printf("元素%d不存在表中\n", key);

    return 0;
}
 

测试结果:

关键字序列:
   8  14   6   9  10    22  34  18  19  31
  40  38  54  66  46    71  78  68  80  85
 100  94  88  96  87
查找46的比较过程如下:
(1)在索引表中折半查找
  第1次比较:在[0,4]中比较元素records[2]:6
  第2次比较:在[0,1]中比较元素records[0]:8
  第3次比较:在[1,1]中比较元素records[1]:14
比较3次,在第2块中查找元素46
(2)在对应块中顺序查找:
40 38 54 66 46 比较5次,在顺序表中查找元素46
元素46的位置是15

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值