/**
* 实验题目:
* 实现索引文件建立和查找算法
* 实验目的:
* 掌握索引文件的基本操作及其算法设计
* 实验内容:
* 编写程序,建立表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:退出