基于哈希算法(平方探测)的学生成绩管理

题目要求

两个部分:

第一个部分

要求实现哈希表,平方探测,实现四个函数功能:插入,查找,对每个插入的内容执行一个回调函数,清空。原题如下:
(Part 1) In the lecture notes we have seen how to implement symbol tables using Hash tables. In the version we present in the lecture notes, we use the technique of separate chaining to resolve collisions. We shall call this version 1.0.
Implement version 2.0 of symtabADT, in which you use quadratic probing (instead of separate chaining) for collision resolution. You should use F(i)=i2 in your implementation. Also you should set the table size at 51. You should use the following hash function.

int Hash(char *s, int n) {
 unsigned long hashcode = 0UL;
 for (int i=0; s[i]!='\0'; i++) hashcode = (hashcode<<6) + (unsigned long) s[i];
 return (int) (hashcode % n);
}

In your implementation, you should use the following definition for struct
symtabCDT:

typedef struct bucketT { 
 int inUse; // This is 1 if the bucket is in use, or 0 otherwise
 char *key;
 void *value; } bucketT;
struct symtabCDT { bucketT bucket[nBuckets]; };

where nBuckets is constant 51 defined using #define in symtab.c.
You shall need to implement at least four functions: EmptySymbolTable, Enter, Lookup, and ForEachEntryDo.
Note: you only need to submit symtab.c that implements version 2.0 of symtabADT.

第二部分

读第一个txt得到成绩、学号、姓名,这是要利用上衣部分的哈希表。以学号(文本形式)为键,学生结构体指针为key。读第二个txt,在哈希表中查找,并修改成绩信息。然后乱序打印。原题如下:

(Part 2) Prof. Chan is teaching a course that is open to both postgraduate and undergraduate students. Prof. Chan decides to use different scales for postgraduate and undergraduate students to convert from numeric marks to
grades.
The class list with marks of individual students is stored in a student data file studentData.txt. The format of the student data file is shown as follows:
218432
CHAN TAI MAN
78
200987
CHEUNG MAN MING
90
217748
MAN TAI SUN
75
216639
YEUNG WING KEUNG
98

A student’s information is stored in four separate lines in the student data file. The first line is a 6-digit student number, the second line is the student’s name, and the third line the student’s mark (which is an integer). Whether a student is a postgraduate student or an undergraduate student is indicated by his or her student number: if the second digit is 0, then the student is a postgraduate student; otherwise, the student is an undergraduate student. The total number of students is not known in advance, so you need to read the file until the end of file is reached.
There is another file called the data correction file dataCorrection.txt. If there is any mistake in the studentData.txt file, then the correction information will appear in the data correction file for correction purpose. A student’s information is stored in two separate lines in the data correction file. The first line is a 6-digit student number, and the second line the student’s correct mark (which is an integer). We assume that there is only one data correction file for all teachers, that is, it might contain information about a student whose student number does not appear in the original student data file. This is because it is actually a correction for the student data file of another teacher. If this happens, the you can simply ignore it. The following is an example of the data correction file:
218432
80
200100
82
216639
98

In this case the student whose student number is 200100 does not appear in the data file, so it can be ignored.Write a program that first reads the student data file and then the data correction file, and outputs the grades of each of the students in a file. The following is a sample output for the above input file (the order is not important).
218432 CHAN TAI MAN
B
200987 CHEUNG MAN MING
A
217748 MAN TAI SUN
B
216639 YEUNG WING KEUNG
A

  1. Note 1

You must use the following implementation:

  1. You must first use typedef to define a structure type StudentT for a structure with 3 fields.
    The first field sName is a string that stores the name of the student.
    The second field level is a value of type studentLevelT(studentLevelT level), where studentLevelT is an enum type defined as
    typedef enum {UG, PG} studentLevelT;
    The last field mark is an int value (int mark) that stores the student’s examination mark.
    2.There is a function char getGrade(StudentT) to determine the grade for each of the students.
    The conversion schemes for undergraduates and postgraduates are as follows:
    …略…
  2. Note 2

You should use a symbol table to store the students’ information in your program. The key is the student IDs. The data stored in the table should be pointers of type StudentT*, which point to structures of type StudentT. For simplicity, you can assume that the table will never be full.
Your program should work well using the symtab.h and symtab.c in the lecture notes and in Part 1 of the question.

  1. Note 3

To output the grades of all students, you must use a call back function
void displayStudentNameAndGrade(char, StudentT)**
to display all entries in the table (the order is not important). You may use the mapping function forEachEntryDo defined in the lecture notes.

解题

main.c中读取文件等基本操作,注意:文本最后留空行;读到的字符串,每一行结束夫前还有个回车要删掉。

#include <stdio.h>
#include "symtab.h"
#include "Student.h"
#include <string.h>
#define MAX_LINE 20//姓名最长为20
char names[nBuckets][MAX_LINE];//记录学生姓名
char ids[nBuckets][10];//记录学生id(学号)
StudentT students[nBuckets];//记录所有学生
int idx = 0;
symtabCDT cdt;

int main()
{
    char buf[1024];  /*缓冲区*/
    FILE* fp;            /*文件指针*/
    int len;             /*行字符个数*/
    fp = fopen("StudentData.txt", "r");
    //读数据
    while (fgets(buf, 1024, fp) != NULL)
    {
        //获取学号
        len = (int)strlen(buf);
        buf[len - 1] = '\0';  /*去掉换行符*/
        strncpy(ids[idx], buf, 7);
        students[idx].id = ids[idx];
        //获取名字
        fgets(buf, 1024, fp);
        len = (int)strlen(buf);
        buf[len - 1] = '\0';  /*去掉换行符*/
        strncpy(names[idx], buf, len);
        students[idx].sName = names[idx];
        //获取成绩
        fgets(buf, 1024, fp);
        len = (int)strlen(buf);
        buf[len - 1] = '\0';  /*去掉换行符*/
        students[idx].mark = 0;
        for (int j = 0; j < len-1; j++) {
            students[idx].mark *= 10;
            students[idx].mark += (buf[j] - '0');
        }
        //判断研究生还是本科
        if (students[idx].id[1] == '0')
            students[idx].studentLevel = PG;
        else
            students[idx].studentLevel = UG;
        //插入到哈希表中
        Enter(&cdt, students[idx].id, &students[idx]);
        
        idx++;
    }
    while (fgets(buf, 1024, fp) != NULL)
    {
        //获取学号
        len = (int)strlen(buf);
        buf[len - 1] = '\0';  /*去掉换行符*/
        StudentT* p = Lookup(&cdt, buf);
        if (p == NULL)
            fgets(buf, 1024, fp);
        else {
            //获取成绩
            fgets(buf, 1024, fp);
            len = (int)strlen(buf);
            buf[len - 1] = '\0';  /*去掉换行符*/
            int a = 0;
            for (int j = 0; j < len - 1; j++) {
                a *= 10;
                a += (buf[j] - '0');
                p->mark = a;
            }
        }
    }
    ForEachEntryDo(&cdt, displayStudentNameAndGrade);
    //printf("%p", Lookup(&cdt, "218432"));
    return 0;
}

student.c和.h

//.h
#ifndef  STUDENT 
#define STUDENT
typedef enum studentLevelT { UG, PG } studentLevelT;
typedef struct StudentT {
	char* sName;
	char* id;
	studentLevelT studentLevel;
	int mark ;
}StudentT;

char getGrade(StudentT st);
void displayStudentNameAndGrade(char* grade, StudentT* st);
#endif // ! STUDENT 
//.c
#include "symtab.h"
#include <string.h>
#include "Student.h"
void EmptySymbolTable(symtabCDT* table) {
    for (int i = 0; i < nBuckets; i++) {
        table->bucket[i].inUse = 0;
    }
}
void Enter(symtabCDT* table, char* key, void* value) {
    int v = Hash(key, nBuckets);
    if (table->bucket[v].inUse==0)
    {    
        table->bucket[v].inUse = 1;
        table->bucket[v].key = key;
        table->bucket[v].value = value;
    }
    else {
        //进行平方探测
        for (int i = 1; ; i++)
        {
            if (v + i * i < nBuckets)
            {
                if (table->bucket[v + i * i].inUse == 0)
                {//找到了
                    table->bucket[v + i * i].inUse = 1;
                    table->bucket[v + i * i].key = key;
                    table->bucket[v + i * i].value = value;
                    break;
                }
            }
            else
            {
                int temp = (v + i * i) % nBuckets;
                if (table->bucket[temp].inUse == 0)
                {
                    table->bucket[temp].inUse = 1;
                    table->bucket[temp].key = key;
                    table->bucket[temp].value = value;
                    break;
                }
            }
            if (v - i * i >= 0)
            {
                if (table->bucket[v - i * i].inUse == 0)
                {
                    table->bucket[v - i * i].inUse = 1;
                    table->bucket[v - i * i].key = key;
                    table->bucket[v - i * i].value = value;
                    break;
                }
            }
            else
            {
                int temp = (v - i * i) % nBuckets + nBuckets;
                if (table->bucket[temp].inUse == 0)
                {
                    table->bucket[temp].inUse = 1;
                    table->bucket[temp].key = key;
                    table->bucket[temp].value = value;
                    break;
                }
            }
        }
    }
}
void* Lookup(symtabCDT* table, char* key) {
    int v = Hash(key, nBuckets);
    if (table->bucket[v].inUse == 1 
        && strcmp(table->bucket[v].key, key) == 0) {
        return table->bucket[v].value;
    }
    else
    { //进行平方探测
        for (int i = 1; i< nBuckets; i++)
        {
            if (v + i * i < nBuckets)
            {
                if (table->bucket[v + i * i].inUse == 1 
                    && strcmp(table->bucket[v + i * i].key ,key)==0)
                {//找到了
                    return table->bucket[v + i * i].value;
                    break;
                }
            }
            else
            {
                int temp = (v + i * i) % nBuckets;
                if (table->bucket[temp].inUse == 1
                    && strcmp(table->bucket[temp].key ,key)==0)
                {
                    return table->bucket[temp].value;
                    break;
                }
            }
            if (v - i * i >= 0)
            {
                if (table->bucket[v - i * i].inUse == 1
                    && strcmp(table->bucket[v - i * i].key,key)==0)
                {
                    return table->bucket[v - i * i].value;
                    break;
                }
            }
            else
            {
                int temp = (v - i * i) % nBuckets + nBuckets;
                if (table->bucket[temp].inUse == 1
                    && strcmp(table->bucket[temp].key,key)==0)
                {
                    return table->bucket[temp].value;
                    break;
                }
            }
        }
    }
    return NULL;
}
int Hash(char* s, int n) {
    unsigned long hashcode = 0UL;
    for (int i = 0; s[i] != '\0'; i++) hashcode = (hashcode << 6) + (unsigned long)s[i];
    return (int)(hashcode % n);
}

void ForEachEntryDo(symtabCDT* table, void(*func)()) {
    for (int i = 0; i < nBuckets; i++) {
        if (table->bucket[i].inUse == 1) {
            func(' ',table->bucket[i].value);
        }
    }
    return;
}

symtab.c和symtab.h

//.h
#ifndef sy
#define sy
#define nBuckets 51
#include "Student.h"
typedef struct bucketT {
    int inUse; // This is 1 if the bucket is in use, or 0 otherwise
    char* key;
    void* value;
} bucketT;
typedef struct symtabCDT { 
    bucketT bucket[nBuckets]; 
}symtabCDT;
void EmptySymbolTable(symtabCDT* cdt);
void Enter(symtabCDT* table, char* key, void* value);
void* Lookup(symtabCDT* table, char* key);
int Hash(char* s, int n);
void ForEachEntryDo(symtabCDT* table, void (*func)());
#endif // !sy
//.c
#include "symtab.h"
#include <string.h>
#include "Student.h"
void EmptySymbolTable(symtabCDT* table) {
    for (int i = 0; i < nBuckets; i++) {
        table->bucket[i].inUse = 0;
    }
}
void Enter(symtabCDT* table, char* key, void* value) {
    int v = Hash(key, nBuckets);
    if (table->bucket[v].inUse==0)
    {    
        table->bucket[v].inUse = 1;
        table->bucket[v].key = key;
        table->bucket[v].value = value;
    }
    else {
        //进行平方探测
        for (int i = 1; ; i++)
        {
            if (v + i * i < nBuckets)
            {
                if (table->bucket[v + i * i].inUse == 0)
                {//找到了
                    table->bucket[v + i * i].inUse = 1;
                    table->bucket[v + i * i].key = key;
                    table->bucket[v + i * i].value = value;
                    break;
                }
            }
            else
            {
                int temp = (v + i * i) % nBuckets;
                if (table->bucket[temp].inUse == 0)
                {
                    table->bucket[temp].inUse = 1;
                    table->bucket[temp].key = key;
                    table->bucket[temp].value = value;
                    break;
                }
            }
            if (v - i * i >= 0)
            {
                if (table->bucket[v - i * i].inUse == 0)
                {
                    table->bucket[v - i * i].inUse = 1;
                    table->bucket[v - i * i].key = key;
                    table->bucket[v - i * i].value = value;
                    break;
                }
            }
            else
            {
                int temp = (v - i * i) % nBuckets + nBuckets;
                if (table->bucket[temp].inUse == 0)
                {
                    table->bucket[temp].inUse = 1;
                    table->bucket[temp].key = key;
                    table->bucket[temp].value = value;
                    break;
                }
            }
        }
    }
}
void* Lookup(symtabCDT* table, char* key) {
    int v = Hash(key, nBuckets);
    if (table->bucket[v].inUse == 1 
        && strcmp(table->bucket[v].key, key) == 0) {
        return table->bucket[v].value;
    }
    else
    { //进行平方探测
        for (int i = 1; i< nBuckets; i++)
        {
            if (v + i * i < nBuckets)
            {
                if (table->bucket[v + i * i].inUse == 1 
                    && strcmp(table->bucket[v + i * i].key ,key)==0)
                {//找到了
                    return table->bucket[v + i * i].value;
                    break;
                }
            }
            else
            {
                int temp = (v + i * i) % nBuckets;
                if (table->bucket[temp].inUse == 1
                    && strcmp(table->bucket[temp].key ,key)==0)
                {
                    return table->bucket[temp].value;
                    break;
                }
            }
            if (v - i * i >= 0)
            {
                if (table->bucket[v - i * i].inUse == 1
                    && strcmp(table->bucket[v - i * i].key,key)==0)
                {
                    return table->bucket[v - i * i].value;
                    break;
                }
            }
            else
            {
                int temp = (v - i * i) % nBuckets + nBuckets;
                if (table->bucket[temp].inUse == 1
                    && strcmp(table->bucket[temp].key,key)==0)
                {
                    return table->bucket[temp].value;
                    break;
                }
            }
        }
    }
    return NULL;
}
int Hash(char* s, int n) {
    unsigned long hashcode = 0UL;
    for (int i = 0; s[i] != '\0'; i++) hashcode = (hashcode << 6) + (unsigned long)s[i];
    return (int)(hashcode % n);
}

void ForEachEntryDo(symtabCDT* table, void(*func)()) {
    for (int i = 0; i < nBuckets; i++) {
        if (table->bucket[i].inUse == 1) {
            func(' ',table->bucket[i].value);
        }
    }
    return;
}

效果

在这里插入图片描述

完整资源

https://download.csdn.net/download/renzemingcsdn/15784637

有问题留言。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清欢_小铭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值