有BUG待调试 编写目的如下
① dump input - file-name fill-factor? data.txt 80 - data.txt 파일내에저장된(id, name, age, grade) 쌍들을입력하여여러분들의파일 (student.dat)에저장(전체쌍의수> 1,000) - student.dat: 첫번째블록(block 0)은header block이며, block 1부터레코드저장. 단, 각block에는101 * fill-factor / 100 만큼의레코드가저장 - data.txt: ASCII 파일로서각field들은하나의줄에표시
② block status - file-name block-number? student.dat 123 - block 123에저장된레코드의수및그수만큼의레코드를예쁘게출력 - block 0일경우에는header block의rec_num과fill_factor를출력할것.
③ sort - 2PMM을이용하여학번에대한오름차순으로정렬하여sorted.dat에저장 (Memory 크기= 1,000개의block을저장할수있다고가정) - sorted.dat에대한block status 명령으로block 내용확인가능
④ search - 찾고자하는학번? 학번입력 → 해당학생을검색후(binary search), 이름과나이, 그리고평점출력
⑤ exit: 종료
FILE:struct.h
#ifndef STRUCT_H
#define STRUCT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int id;
char name[20];
int age;
double grade;
};
struct block
{
struct student record[101];
char fill[44];
int rec_num;
long next;
long prev;
};
struct header
{
int rec_num;
int fill_factor;
char fill[4088];
};
#define SSTU sizeof(struct student)
#define SBLC sizeof(struct block)
#define SHED sizeof(struct header)
#define HEAD1 "------------Students Info------------n"
#define HEAD2 "| Student ID | Name | Age | Grade |n"
#define HEAD3 "|------------|--------|-----|-------|n"
#define FORMAT "| %-6d | %-6s | %-3d | %-1.2lf |n"
#define END "-----------------END-----------------n"
#define SMEMORY 1000 //Memory크기 == 1000 개의 block을 저장할 수 있다
int getnum();
int getfactor();
void dump();
void blockstatus();
int comp(const void *a,const void *b);
void Mergesort(int n1, int n2, int n3);
void sort();
int binsearch(struct block *p, int num, int left, int right);
void search();
void read();
void menu();
#endif
/************************************************************************************************/
FILE:dump.c
#include "struct.h"
int getnum()
{
int num;
int z;
while(1)
{
fflush(stdin); //清除输入缓冲区防止因为scanf读入为字符后enter产生死循环
z = scanf("%d", &num);
if (num < 0)
{
printf("Must > 0nRe_enter,please!n");
continue;
}
else if (num >= 0 && z == 1)
break;
else if (num >= 0 && z == 0)
{
printf("Must be a number!!nRe_enter,please!n");
continue;
}
}
fflush(stdin);
return num;
}
int getfactor() //获得record的%比并返回
{
int n;
while(1)
{
printf("Please enter the %% of recordn");
n = getnum();
if(n > 0 && n <= 100)
break;
else if(n > 100)
{
printf("%Record must < 100n");
continue;
}
}
return n;
}
void dump()
{
FILE *in, *out; //文件指针
struct block *p = NULL; //定义指向block结构体的指针p并赋空值
struct header *head = NULL; //定义header结构体的元素 head;
char filename[20]; //需要转换的TXT文件名称
int blk; //定义block长度
int x; //判断用
char key; //判断用
x = 1;
while(1)
{
printf("TXT파일의 이름을 입력하세요!n");
scanf("%s", filename);
if ( (in = fopen (filename, "r")) == NULL) //如果无法找到TXT文件
{
printf("Can't open file '%s'. Please make sure the name.n", filename);
getchar();
getchar();
break;
}
if ( (out = fopen("student.dat", "rb+")) != NULL) //如果学生数据文件存在
x = 0;
else
{
printf("Try to open file 'student.dat',but can't find it!n");
printf("파일'student.dat'새로 만들래");
getchar();
while(1)
{
printf("[Y]/[N]?");
scanf("%c", &key);
if (key == 'y' || key == 'Y')
{
if ( (out = fopen ("student.dat", "wb+")) == NULL) //如果无法创建
printf("Can't creat 'student.dat'!n");
else //创建成功
{
printf("File 'student.dat' has been created!n");
x = 0;
}
break;
}
else if (key == 'n' || key == 'N')
{
printf("취소했다!n");
fclose(in);
getchar();
getchar();
break;
}
}
}
if (x == 0) //如果文件被成功打开
{
head = (struct header*)malloc(SHED);
head->fill_factor = getfactor(); //获得record可使用的百分比
head->rec_num = 0; //初始record为0
x = (int)(101 * head->fill_factor / 100); //计算可使用的record个数
p = (struct block*)malloc(SBLC); //申请动态内存空间p,大小为block结构体大小
fseek(out,SHED,0); //跳过结构体header文件头(block0),最后写入
blk = 0;
while(!feof(in))
{
blk += 1; //块自增
p->rec_num = 0;
while(p->rec_num < x && !feof(in)) //当record小于可用数且txt文件不为结尾时
{
//读取txt文件内的数据
if(fscanf(in, "%d %s %d %lf", &p->record[p->rec_num].id, p->record[p->rec_num].name,
&p->record[p->rec_num].age, &p->record[p->rec_num].grade) == EOF)
break;
head->rec_num += 1; //record总数目+1
p->rec_num += 1; //当前块record数目+1
}
if(feof(in))p->next = 1;
else p->next = blk + 1;
if(blk > 1)p->prev = blk - 1;
else p->prev = 1;
if(!feof(in) || p->rec_num > 0)fwrite(p, SBLC, 1, out);
}
fseek(out, 0, 0);
fwrite(head, SHED, 1, out);
fseek(out, SHED + 101*SSTU + 48, 0); //重新写入第一个block中的链表指向结尾
fwrite(&blk, 4, 1, out);
free(p);
free(head);
fclose(in);
fclose(out);
printf("데이터 파일 만들어되었습니다.");
getchar();
break;
}
}
}
void blockstatus(char FILENAME[])
{
FILE *fp;
struct block *p = NULL; //指向block指针p
struct header *h = NULL; //指向header指针h
int blknum; //block-number
int i, j;
if ((fp = fopen(FILENAME, "rb")) == NULL)
{
printf("Can't find '%s'!", FILENAME);
getchar();
}
else
{
printf("Please enter the block number :");
blknum = getnum();
printf("blknum = %dn",blknum);
if (blknum != 0) //当block位置不为0
{
p = (struct block*)malloc(SBLC); //申请动态空间
fseek(fp, blknum*SBLC, 0);
if (fread(p, SBLC, 1, fp) != 0) //当该block存在时
{
printf(HEAD1);
printf(HEAD2);
printf(HEAD3);
j = 4;
for(i = 0; i < p->rec_num; i++)
{
printf(FORMAT, p->record[i].id, p->record[i].name, p->record[i].age, p->record[i].grade);
j += 1;
if (j == 24)
{
printf("Press enter to next page!n");
getchar();
j = 0 ;
}
}
printf(END);
printf("이 block안에 전체record의 개수는 %d 이다.n", p->rec_num);
getchar();
}
else
{
printf("Out of block!n");
getchar();
}
free(p);
}
else if (blknum == 0) //当block位置为0
{
h = (struct header*)malloc(SHED);
fseek(fp, 0, 0);
fread(h, SHED, 1, fp);
printf("파일안에 저장되어 있는 record개수는 %d 이다.n", h->rec_num);
printf("block 용량 대비는 %d 이다.n", h->fill_factor);
free(h);
getchar();
}
}
}
/************************************************************************************************/
FILE:sort.c
#include "struct.h"
int comp(const void *a,const void *b)
{
struct block *aa = (struct block*)a;
struct block *bb = (struct block*)b;
if (aa[0].record->id < bb[0].record->id) return -1;
else if (aa[0].record->id> bb[0].record->id) return 1;
else return 0;
}
/*void Quicksort(struct student *p, int left, int right) //QuickSort but i will not use it
{
int pivot;
int i;
int j;
struct student temp;
if(left < right)
{
i = left;
j = right;
pivot = p[(i + j) / 2].id; //设定keyword为中间数的值
while(i < j)
{
for(;(i < right)&&(p[i].id < pivot);i++); //从左往右持续寻找直到当前数小于Keyword
for(;(j > left)&&(p[j].id > pivot);j--); //从右往左持续寻找直到当前数大于Keyword
if (i <= j) //当满足上面条件时 左 仍然小于等于 右
{
//swap 左 右
temp = p[i];
p[i] = p[j];
p[j] = temp;
i++;
j--;
}
}
if (i < right) //当左边没有达到右边时
Quicksort(p, i, right);
if (j > left) //当右边没有达到左边时
Quicksort(p, left, j);
}
}
*/
void Mergesort(int n1, int n2, int n3) //2PMM 之 阶段2 归并排序(Merge Sort)
{
FILE *tmp1, *tmp2;
FILE *fp;
struct student loser;
struct student p1;
struct student p2;
char TempFile[50];
int i, j;
sprintf(TempFile, "Temp_%d", n1);
tmp1 = fopen(TempFile,"rb");
sprintf(TempFile, "Temp_%d", n2);
tmp2 = fopen(TempFile,"rb");
sprintf(TempFile, "Temp_%d", n3);
fp = fopen(TempFile,"wb");
fread(&p1, SSTU, 1, tmp1);
fread(&p2, SSTU, 1, tmp2);
while(!feof(tmp1) && !feof(tmp2))
{
if(p1.id <= p2.id)
{
fwrite(&p1, SSTU, 1, fp);
if((fread(&p1, SSTU, 1, tmp1)) != 0)
continue;
}
else if(p1.id > p2.id )
{
fwrite(&p2, SSTU, 1, fp);
if((fread(&p2, SSTU, 1, tmp2)) != 0)
continue;
}
}
if(feof(tmp1))
{
while(fread(&p2, SSTU, 1, tmp2) != 0)
{
fwrite(&p2, SSTU, 1, fp);
}
}
if(feof(tmp2))
{
while(fread(&p1, SSTU, 1, tmp1) != 0)
{
fwrite(&p1, SSTU, 1, fp);
}
}
fclose(tmp1);
fclose(tmp2);
fclose(fp);
sprintf(TempFile, "Temp_%d", n1);
remove(TempFile);
sprintf(TempFile, "Temp_%d", n2);
remove(TempFile);
}
void sort()
{
FILE *in, *out, *t;
int cntn;
char TempFile[50];
struct block *p;
struct header *h;
struct student *temp;
struct student st;
int i, j, k;
cntn = i = k = 0;
in = fopen("student.dat", "rb");
p = (struct block*)malloc(SBLC);
fseek(in, SHED, 0); //跳过BLOCK O将在最后写入该位置
//先进行2PMM第一步快速排序 因为BLOCK内的其他元素不会改变为节约内存仅提取出学生数据
temp = (struct student*)malloc((SMEMORY - 3 ) * 101 * SSTU);
while(!feof(in))
{
fread(p, SBLC, 1, in);
while ((!feof(in)) && i < (SMEMORY - 3 ) * 101)
{
for(j =0; j < p->rec_num && i < (SMEMORY - 3 ) * 101; i++, j++)
temp[i] = p->record[j];
fread(p, SBLC, 1, in);
}
//Quicksort(temp, 0, i - 1); //if use Quciksort();
qsort(temp,i,SSTU,comp); //if use qsort();
sprintf(TempFile, "Temp_%d", cntn);
t = fopen(TempFile, "wb");
for(k = 0; k < i; k++)
fwrite(&temp[k], SSTU, 1, t);
cntn++;
fclose(t);
i = 0;
if(j< p->rec_num)
{
while(j < p->rec_num)
{
temp[i] = p->record[j];
i++;
j++;
}
}
}
free(temp);
i = 0, j = cntn;
while(cntn > 1)
{
Mergesort(i,i+1, j);
i = i + 2;
j++;
cntn -= 1;
}
if(cntn <= 1)
{
h = (struct header*)malloc(SHED);
sprintf(TempFile, "Temp_%d", j - 1);
t = fopen(TempFile, "rb");
out = fopen("sorted.dat","wb");
fseek(in, 0, 0);
fread(h, SHED, 1, in);
fwrite(h, SHED, 1, out);
fread(p, SBLC, 1, in);
while(!feof(in))
{
for(i = 0; i < p->rec_num; i++)
{
fread(&st, SSTU, 1, t);
p->record[i] = st;
//printf(FORMAT, p->record[i].id, p->record[i].name, p->record[i].age, p->record[i].grade);
}
fwrite(p, SBLC, 1, out);
fread(p, SBLC, 1, in);
}
fclose(out);
fclose(t);
remove(TempFile);
}
fclose(in);
free (p);
printf("Sort end!n");
getchar();
}
int binsearch(struct block *p, int num, int left, int right)
{
int middle;
while (left <= right)
{
middle = (left + right) / 2;
switch( (p->record[middle].id < num) ? -1 : (p->record[middle].id == num) ? 0 : 1)
{
case -1: left = middle + 1;break;
case 0 : return middle;
case 1 : right = middle - 1;
}
}
return -1;
}
void search()
{
FILE *fp;
struct block *p;
int num;
int i;
printf("Please enter a num:");
num = getnum();
fp = fopen("sorted.dat", "rb");
i = -1;
p = (struct block*)malloc(SBLC);
fseek(fp, SBLC, 0);
while((fread(p, SBLC, 1, fp)) != 0)
{
if(p->record[0].id <= num && num <= p->record[p->rec_num-1].id)
{
i = binsearch(p, num, 0, p->rec_num);
break;
}
}
if(i == -1)
{
printf("Can't find it!n");
}
else
{
printf(HEAD1);
printf(HEAD2);
printf(HEAD3);
printf(FORMAT, p->record[i].id, p->record[i].name, p->record[i].age, p->record[i].grade);
printf(END);
}
fclose(fp);
free(p);
getchar();
}
/************************************************************************************************/
FILE:main.c
/*
* File: main.c
* Author: section
*
* Created on 2011年4月30日, 下午9:46
*/
#include "struct.h"
void menu()
{
system("cls");
printf("----------------MENU-----------------n");
printf("| 1.Block 검색 |n");
printf("| 2.Sort |n");
printf("| 3.Block 검색(Sorted) |n");
printf("| 4.학생 검색 |n");
printf("| 5.종료 |n");
printf("-------------------------------------n");
printf("|!*0.데이터 파일 만들기 |n");
printf("------------------학새관리-Ver 1.0---n");
}
int main(void)
{
char key;
while(1)
{
fflush(stdin);
menu();
scanf("%c", &key);
if(key == '5' || key == 'q' || key == 'Q')
break;
switch(key)
{
case '1': blockstatus("student.dat");break;
case '2': sort();break;
case '3': blockstatus("sorted.dat");break;
case '4': search();break;
case '0': dump();break;
case '6': read();break;
}
}
return 0;
}