实现索引文件建立和查找算法

/**
*    实验题目:
*        实现索引文件建立和查找算法
*    实验目的:
*        掌握索引文件的基本操作及其算法设计
*    实验内容:
*        编写程序,建立表12.1中学生成绩记录对应的主文件data.dat,
*    要求完成以下功能:
*    1、输出主文件中的学生记录
*    2、建立与主文件相对应的索引文件,其中每个记录由两个字段组成:
*    学号no及该学生记录在数据文件中的相应位置offset。索引文件中的
*    记录按学号no升序排列。
*    3、输出索引文件全部记录
*    4、根据用户输入的学号,在索引文件中采用折半查找法找到对应记录
*    号,再通过主文件输出记录。
*/

#include <stdio.h>

#define MAX_REC 100                             //  最多的记录个数

typedef struct index
{
    int no;                                     //  学号
    long offset;                                //  主文件中的记录号
}index;                                         //  索引文件类型

/*————-设计学生记录类型————–*/
typedef struct
{
    int no;                 //  学号
    char name[10];          //  姓名
    int age;                //  年龄
    char sex[3];            //  性别
    int chinese_deg;        //  语文成绩
    int math_deg;           //  数学成绩
    int english_deg;        //  英语成绩
}stud_type;

/*————-将st数组中的学生记录写入到二进制文件stud.dat文件中————–*/
//  由数组st中的n个学生成绩记录建立主文件stud.dat
static void write_file(int n)
{
    int i;
    FILE *fp;
    stud_type st[] = {
        {1, “陈华”, 20, “男”, 78, 99, 84},
        {5, “张明”, 21, “男”, 76, 89, 88},
        {8, “王英”, 22, “女”, 78, 79, 80},
        {3, “刘丽”, 19, “女”, 82, 59, 81},
        {2, “许可”, 18, “女”, 90, 90, 90},
        {4, “陈军”, 23, “男”, 88, 94, 94},
        {7, “朱军”, 24, “男”, 87, 99, 95},
        {6, “李鹏”, 22, “男”, 72, 93, 92},
    };

    fp = fopen(“stud.dat”, “wb”);       //  模式:wb以只写方式打开或新建一个二进制文件,只允许写数据
    if(fp == NULL)
    {
        printf(“\t提示:不能创建stud.dat文件\n”);
        return;
    }

    for(i = 0; i < n; i++)
        fwrite(&st[i], 1, sizeof(stud_type), fp);

    fclose(fp);

    printf(”  提示:文件stud.dat创建完毕\n”);
}

/*————-输出主文件stud.dat中的全部记录————–*/
static void output_main_file(void)
{
    FILE *fp;
    stud_type st;
    int i = 1;

    fp = fopen(“stud.dat”, “rb”);
    if(fp == NULL)
    {
        printf(”  提示:不能读主文件stud.dat\n”);
        return;
    }
    printf(“——————-学生成绩表——————-\n”);
    printf(“记录号  学号  姓名  年龄 性别  语文  数学  英语\n”);
    while(fread(&st, sizeof(stud_type), 1, fp) == 1)
    {
        printf(“%3d%7d%8s%5d%5s%6d%6d%6d\n”, i, st.no, st.name, st.age, st.sex,
               st.chinese_deg, st.math_deg, st.english_deg);
        i++;
    }
    fclose(fp);
}

/*————-对含有n个记录的索引数组R按学号no递增排序————-*/
//  采用直接插入排序算法对idx[0…n-1]按学号递增排序
/*
idx[0]: 学号 = 1, 主文件中记录号 = 1
idx[1]: 学号 = 5, 主文件中记录号 = 2
idx[2]: 学号 = 8, 主文件中记录号 = 3
idx[3]: 学号 = 3, 主文件中记录号 = 4
idx[4]: 学号 = 2, 主文件中记录号 = 5
idx[5]: 学号 = 4, 主文件中记录号 = 6
idx[6]: 学号 = 7, 主文件中记录号 = 7
idx[7]: 学号 = 6, 主文件中记录号 = 8
*/
static void insert_sort(index idx[], int n)
{
    int i, j;
    index temp;

    for(i = 1; i < n; i++)
    {
        temp = idx[i];
        j = i – 1;
        printf(“插入排序时:j = %d, temp.no = %d, idx[%d].no = %d\n”, j, temp.no, j, idx[j].no);
        while(j >= 0 && temp.no < idx[j].no)
        {
            idx[j + 1] = idx[j];
            j–;
        }
        idx[j + 1] = temp;
    }
}

/*————-建立索引文件index.dat————–*/
static void create_idx_file(void)
{
    FILE *m_file, *idx_file;
    index idx[MAX_REC];
    stud_type st;
    int n = 0;                                              //  n累计从stud.dat文件中读出的记录个数
    int i;

    m_file = fopen(“stud.dat”, “rb”);
    if(m_file == NULL)
    {
        printf(”  提示:不能打开主文件stud.dat\n”);
        return;
    }

    idx_file = fopen(“index.dat”, “wb”);
    if(idx_file == NULL)
    {
        printf(”  提示:不能建立索引文件index.dat\n”);
        return;
    }

    i = 0;
    while(fread(&st, sizeof(stud_type), 1, m_file) != NULL)
    {
        idx[i].no = st.no;                                  //  学号
        idx[i].offset = ++n;                                //  主文件中的记录号
        i++;
    }
    printf(“排序前:\n”);
    for(i = 0; i < n; i++)
        printf(”  学号 = %d, 主文件中记录号 = %d\n”, idx[i].no, idx[i].offset);

    insert_sort(idx, n);                                    //  对idx数组按照no值排序

    printf(“排序后:\n”);
    for(i = 0; i < n; i++)
        printf(”  学号 = %d, 主文件中记录号 = %d\n”, idx[i].no, idx[i].offset);

    rewind(idx_file);                                       //  使文件idx_file的位置指针指向文件开始
    for(i = 0; i < n; i++)                                  //  将索引记录写入索引文件
        fwrite(&idx[i], sizeof(index), 1, idx_file);

    fclose(m_file);
    fclose(idx_file);

    printf(”  提示:索引文件index.dat建立完毕\n”);
}

/*————-输出索引文件index.dat中的全部记录————–*/
static void output_idx_file(void)
{
    FILE *idx_file;
    index i_rec;
    int i = 0;

    printf(”    ————–学生索引表————–\n”);
    printf(“\t学号                    记录号\n”);

    idx_file = fopen(“index.dat”, “rb”);
    if(idx_file == NULL)
    {
        printf(”  提示:不能读索引文件index.dat\n”);
        return;
    }
    while(fread(&i_rec, sizeof(index), 1, idx_file) == 1)
        printf(“\t%2d                    %5d\n”, i_rec.no, i_rec.offset);

    fclose(idx_file);
}

/*—————读取索引文件index.dat中的n个记录并存入到idx数组中—————-*/
static void read_index_file(index idx[MAX_REC], int &n)
{
    FILE *idx_file;
    int file_len;

    idx_file = fopen(“index.dat”, “rb”);
    if(idx_file == NULL)
    {
        printf(”  提示:索引文件indx.dat不能打开\n”);
        return;
    }
    fseek(idx_file, 0, SEEK_END);                           //  设置文件指针idx_file的位置(文件结尾)
    file_len = ftell(idx_file);                             //  求出文件长度
    printf(“索引文件长度 = %d\n”, file_len);
    rewind(idx_file);                                       //  使文件idx_file的位置指针指向文件开始
    n = file_len / sizeof(index);                           //  求出文件中的记录个数
    printf(“索引文件中的记录个数 = %d\n”, n);
    fread(idx, sizeof(index), n, idx_file);
    fclose(idx_file);
}

/*———-在含有n个记录的索引文件中采用折半查找算法查找学号为no记录的记录号————–*/
static int search_num(index idx[], int n, int no)
{
    int low = 0;
    int high = n – 1;
    int mid;

    while(low <= high)
    {
        mid = (low + high) / 2;
        if(idx[mid].no > no)
            high = mid – 1;
        else if(idx[mid].no < no)
            low = mid + 1;
        else                            //  idx[mid].no == no
            return idx[mid].offset;     //  主文件中的记录号
    }

    return -1;
}

/*————-输出用户指定学号的学生记录————–*/
static void find_student_by_no(void)
{
    FILE *m_file;                                           //  文件指针
    index idx[MAX_REC];                                     //  索引记录数组
    int n;                                                  //  索引文件中的记录个数
    int no;                                                 //  学号
    int result;
    stud_type st;

    m_file = fopen(“stud.dat”, “rb+”);
    if(m_file == NULL)
    {
        printf(”  提示:主文件stud.dat中没有任何记录\n”);
        return;
    }

    read_index_file(idx, n);                                //  读取索引数组idx
    printf(“读取索引文件记录为:\n”);
    for(int i = 0; i < n; i++)
    {
        printf(”  学号 = %d, 记录号 = %d\n”, idx[i].no, idx[i].offset);
    }
    printf(“\n”);
    printf(“输入学号:”);
    scanf(“%d”, &no);
    result = search_num(idx, n, no);
    if(result == -1)
        printf(”  提示:学号%d不存在!\n”, no);
    else
    {
        printf(“学号为%d的学生,在主文件中的记录号为%d\n”, no, result);
        fseek(m_file, (result – 1) * sizeof(stud_type), SEEK_SET);      //  设置文件指针m_file的位置
        // 由记录号直接跳到主文件中对应的记录
        fread(&st, sizeof(stud_type), 1, m_file);
        printf(“学号  姓名  年龄 性别  语文  数学  英语\n”);
        printf(“%2d%8s%5d%5s%6d%6d%6d\n”, st.no, st.name, st.age, st.sex,
               st.chinese_deg, st.math_deg, st.english_deg);
    }
}

int main(void)
{
    int n = 8;                                              //  n为实际学生人数
    int sel;

    printf(“建立主文件\n”);
    write_file(n);
    do
    {
        printf(“1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出”);
        scanf(“%d”, &sel);
        switch(sel)
        {
        case 1:
            output_main_file();
            break;
        case 2:
            create_idx_file();
            break;
        case 3:
            output_idx_file();
            break;
        case 4:
            find_student_by_no();
            break;
        }
    }while(sel != 0);

    return 0;
}
测试结果:

建立主文件
  提示:文件stud.dat创建完毕
1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出1
——————-学生成绩表——————-
记录号  学号  姓名  年龄 性别  语文  数学  英语
  1           1     陈华   20    男      78     99     84
  2           5     张明   21    男      76     89     88
  3           8     王英   22    女      78     79     80
  4           3     刘丽   19    女      82     59     81
  5           2     许可   18    女      90     90     90
  6           4     陈军   23    男      88     94     94
  7           7     朱军   24    男      87     99     95
  8           6     李鹏   22    男      72     93     92
1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出2
排序前:
  学号 = 1, 主文件中记录号 = 1
  学号 = 5, 主文件中记录号 = 2
  学号 = 8, 主文件中记录号 = 3
  学号 = 3, 主文件中记录号 = 4
  学号 = 2, 主文件中记录号 = 5
  学号 = 4, 主文件中记录号 = 6
  学号 = 7, 主文件中记录号 = 7
  学号 = 6, 主文件中记录号 = 8
插入排序时:j = 0, temp.no = 5, idx[0].no = 1
插入排序时:j = 1, temp.no = 8, idx[1].no = 5
插入排序时:j = 2, temp.no = 3, idx[2].no = 8
插入排序时:j = 3, temp.no = 2, idx[3].no = 8
插入排序时:j = 4, temp.no = 4, idx[4].no = 8
插入排序时:j = 5, temp.no = 7, idx[5].no = 8
插入排序时:j = 6, temp.no = 6, idx[6].no = 8
排序后:
  学号 = 1, 主文件中记录号 = 1
  学号 = 2, 主文件中记录号 = 5
  学号 = 3, 主文件中记录号 = 4
  学号 = 4, 主文件中记录号 = 6
  学号 = 5, 主文件中记录号 = 2
  学号 = 6, 主文件中记录号 = 8
  学号 = 7, 主文件中记录号 = 7
  学号 = 8, 主文件中记录号 = 3
  提示:索引文件index.dat建立完毕
1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出3
    ————–学生索引表————–
        学号                    记录号
         1                        1
         2                        5
         3                        4
         4                        6
         5                        2
         6                        8
         7                        7
         8                        3
1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出4
索引文件长度 = 64
索引文件中的记录个数 = 8
读取索引文件记录为:
  学号 = 1, 记录号 = 1
  学号 = 2, 记录号 = 5
  学号 = 3, 记录号 = 4
  学号 = 4, 记录号 = 6
  学号 = 5, 记录号 = 2
  学号 = 6, 记录号 = 8
  学号 = 7, 记录号 = 7
  学号 = 8, 记录号 = 3

输入学号:5
学号为5的学生,在主文件中的记录号为2
学号  姓名  年龄 性别  语文  数学  英语
 5      张明   21     男     76      89     88
1:输出主文件 2:建索引文件 3:输出索引文件 4:按学号查找 0:退出

    原文作者:查找算法
    原文地址: https://blog.csdn.net/xiezhi123456/article/details/87805357
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞