一、系统特点
亮点1:双语交互界面,系统可适性好。
教师管理系统:
身份选择、密钥对证、系统语言选择:
中文交互界面:
开辟空间:
添加并查找学生信息:
修改并查找学生信息:
删除并查找学生信息:
增扩空间&写入:
格式化:
亮点2:最外层设置身份认证,若为教师则进行密钥认证(strcmp)
若为学生则进入学生管理系统。
亮点3:教师能实现增删改查;而学生只能查看自己的信息,不能修改(只读)。
亮点4:在学生人数过多的情况下,教师能够增添哈希表的单元格数量。
亮点5:使用文件IO,每个学生都有一个其姓名对应的.txt文件保存个人信息。
这样教师在录入完学生的信息后,会自动保存至对应文件,教师退出系统后,学生再进入系统,依旧可以访问到数据。
人性化设计:
亮点6:一个面向用户的管理系统,里面的操作用黑匣子封装,用户无需了解对应的步骤并具体的去操作,简单来说就是抬高C语言的维度,把功能再封装,已达到减少用户操作数的目的。
就比如:
①我在教师模式下,选择添加学生信息,我不需要用户去“输入添加的结构体类型数据——索引并插入哈 希表——打开文件——信息写入文件”这样操作。
我直接封装一个“添加学生信息”,里面有上面的所有功能。
②或是我在学生模式下,查看学生的信息,我不需要用户“创建哈希表——打开文件——读取文件——将 信息写入当前哈希表中——查找”这样操作。
同理,我封装了“查找学生信息”这一个模块,它里面有上面的所有功能。
③退出系统自动进行关闭文件等操作,学生模式下还会自动释放空间无需按多次按钮,多步变一步。
二、源代码:
1.主函数(main.c)
1 #include "../include/main.h"
2
3 int main()
4 {
5 ht * ht1_head = NULL; //哈希表的表头指针
6 link_node ** ht1 = NULL;//指向哈希表的指针
7 int n = 0; //哈希表的单元格数
8 int m = 0; //哈希表的增扩单元格数
9 link_node * ln_new = NULL;//指向链表节点的指针,在子函数里申请空间
10
11 data_type stu1; //存放学生数据的结构体,add子函数要用
12 memset(&stu1,0,sizeof(stu1));//初始化一下
13 char ID[20] = {'\0'}; //存放一个学生的ID,search子函数要用
14 link_node * ln0 = NULL;//定义一个链表节点类型的指针,在search后显示节点内容要用
15
16
17 int a = 0; //用户身份选项
18 char key[6] = "114514";//教师的密钥
19 char s[6]; //输入密钥缓冲区
20 memset(s,0,sizeof(s)); //缓冲区的初始化
21 int op_tch_l = 0; //教师菜单语言选项
22 int op_tch =0; //教师菜单选项
23 int op_stu_l = 0; //学生菜单语言选项
24 int op_stu = 0; //学生菜单选项
25 int file = -1; //文件描述符,注意这里的初始化,不能跟正常打开的描述符搞混
26 int g=0,j=0; //读写指示符,接受read,write的返回值
27 char sss[20]; //保存学生信息的文件的文件名
memset(sss,0,sizeof(sss));
28 printf("Welcome to the XXX university's management system of students information!\n");
29 putchar('\n');
30 printf("Teacher / Student?\n");
31 printf("1---------Teacher\n"); //不使用0,因为a初始化的值是0
32 printf("2---------Student\n");
33 scanf("%d",&a);
34
35 if(a == 1) //开启用户为教师的执行步骤!!!
36 {
37 int i = 0;
38 for(;i<5;i++) //我设定5次的输入密码机会
39 {
40 printf("Please input the key:\n");
41 scanf("%s",s);
42 if ( strncmp(s,key,6) !=0 )
43 {
44 printf("Error key!!!\n");
45 printf("Access denied!!!\n");
46 continue;
47 }
48 else
49 {
50 printf("Correct key!!!\n");
51 printf("Access permitted!\n");
52 putchar('\n');
53 printf("请选择菜单语言\n");
54 printf("Chose the menu language.\n");
55 printf("1---------中文\n");
56 printf("2---------English\n");
57 putchar('\n');
58 scanf("%d",&op_tch_l);
59 if(op_tch_l==1) //用户选择中文菜单
60 {
61
62 //这里开始的就是咱们的老步骤了
63 while(1)
64 {
65 menu_tch1(); //!!!中英文菜单只有菜单和提示语不同
66 printf("请输入操作数:\n"); //其余操作肯定都是一样的
67 scanf("%d",&op_tch);
68 switch(op_tch)
69 {
70 case 0:
71 if(file!=-1) //文件如果开着就给它关了
72 {
73 close(file);
74 }
75 printf("已退出!\n");
76 printf("祝您生活愉快!\n");
77 return 0;
78 case 1:
79 printf("开辟空间:\n");
80 printf("您想开辟多少单元格?\n");
81 scanf("%d",&n);
82 infomalloc1(&ht1,&ht1_head,n);
83 break;
84 case 2://添加完学生信息顺便写入到文件里
85 printf("添加学生信息:\n");
86 printf("请输入想要添加的学生信息:\n");
87 printf("姓名:\n");
88 scanf("%s",stu1.Name);
89 printf("性别:\n");
90 scanf("%s",stu1.Gender);
91 printf("学号:\n");
92 scanf("%s",stu1.ID);
93 printf("成绩:\n");
94 scanf("%s",stu1.Grade);
95 printf("输入完毕!\n");
96 add1(ht1_head,&ln_new,stu1);
sprintf(sss,"%s.txt",stu1.Name);
97 //打开文件
98 file = open(sss,O_RDWR | O_CREAT | O_TRUNC,0664);
99 //写入即可
100 j = write(file,&stu1,sizeof(data_type));
101 if(j==-1)
102 {
103 printf("写入文件失败!\n");
104 return -1;
105 }
106 printf("写入文件成功!\n");
107 break;
108 case 3:
109 printf("修改学生信息:\n");
110 printf("请输入修改后的学生信息\n");
111 printf("姓名:\n");
112 scanf("%s",stu1.Name);
113 printf("性别:\n");
114 scanf("%s",stu1.Gender);
115 printf("学号:\n");
116 scanf("%s",stu1.ID);
117 printf("成绩:\n");
118 scanf("%s",stu1.Grade);
119 printf("输入完毕\n");
120 modify1(ht1_head,stu1);
121 break;
122 case 4:
123 printf("查找学生信息:\n");
124 printf("请输入想要查找的学生学号\n");
125 scanf("%s",ID);
126 ln0 = search1(ht1_head,ID);
127 if(ln0 != NULL)
128 {
129 printf("该学生的信息如下:\n");
130 printf("姓名:%s\n",ln0->stu_data.Name);
131 printf("性别%s\n",ln0->stu_data.Gender);
132 printf("学号:%s\n",ln0->stu_data.ID);
133 printf("成绩:%s\n",ln0->stu_data.Grade);
134 }
135 break;
136 case 5:
137 printf("删除学生信息:\n");
138 printf("请输入想要删除的学生学号:\n");
139 scanf("%s",ID);
140 delete1(&ht1_head,ID);//子函数里实现查找并释放空间
141 break;
142 case 6:
143 printf("增扩空间:\n");
144 printf("请输入想要扩展的行数:\n");
145 scanf("%d",&m);
146 expand1(ht1,&ht1_head,m,n);
147 break;
148 case 999:
149 printf("格式化中...\n");
150 formatting1(&ht1_head,&ht1);
151 break;
152 default:
153 printf("请检查操作数!\n");
154
155 }
156 }//while
157
158 }
159
160 else if(op_tch_l==2) //用户选择英文菜单
162 while(1)
163 {
164 menu_tch2();
165 printf("Please input the option number:\n"); //其余操作肯定都是一样的
166 scanf("%d",&op_tch);
167 switch(op_tch)
168 {
169 case 0://退出系统
170 if(file!=-1) //文件如果开着就给它关了
171 {
172 close(file);
173 }
174 printf("Exited!\n");
175 printf("Have a nice day!\n");
176 return 0;
177 case 1://开辟空间
178 printf("Infomalloc:\n");
179 printf("How many rows shall the hash table have?\n");
180 scanf("%d",&n);
181 infomalloc2(&ht1,&ht1_head,n);
182 break;
183 case 2://添加学生信息
184 printf("Add:\n");
185 printf("Please input the information of this student:\n");
186 printf("Name:\n");
187 scanf("%s",stu1.Name);
188 printf("Gender:\n");
189 scanf("%s",stu1.Gender);
190 printf("ID:\n");
191 scanf("%s",stu1.ID);
192 printf("Grade:\n");
193 scanf("%s",stu1.Grade);
194 printf("Entry completed!\n");
195 add2(ht1_head,&ln_new,stu1);
sprintf(sss,"%s.txt",stu1.Name);
196 file = open(sss,O_RDWR | O_CREAT | O_TRUNC,0664);
197 j = write(file,&stu1,sizeof(data_type));
198 if(j==-1)
199 {
200 printf("write failed!\n");
201 return -1;
202 }
203 printf("write completed!\n");
204 break;
205 case 3://修改学生信息
206 printf("Modify:\n");
207 printf("Please input modified information of this student:\n");
208 printf("Name:\n");
209 scanf("%s",stu1.Name);
210 printf("Gender:\n");
211 scanf("%s",stu1.Gender);
212 printf("ID:\n");
213 scanf("%s",stu1.ID);
214 printf("Grade:\n");
215 scanf("%s",stu1.Grade);
216 printf("Entry completed!\n");
217 modify2(ht1_head,stu1);
218 break;
219 case 4://查找学生信息
220 printf("Search:\n");
221 printf("Please input the ID code of the student you want to seek:\n");
222 scanf("%s",ID);
223 ln0 = search2(ht1_head,ID);
224 if(ln0 != NULL)
225 {
226 printf("The student's information is as follows:\n");
227 printf("Name:%s\n",ln0->stu_data.Name);
228 printf("Gender:%s\n",ln0->stu_data.Gender);
229 printf("ID:%s\n",ln0->stu_data.ID);
230 printf("Grade:%s\n",ln0->stu_data.Grade);
231 }
232 break;
233 case 5://删除学生信息
234 printf("Delete:\n");
235 printf("Please input the ID code of the student you want to delete:\n");
236 scanf("%s",ID);
237 delete2(&ht1_head,ID);//子函数里实现查找并释放空间
238 break;
239 case 6://增扩空间
240 printf("Expand:\n");
241 printf("How many rows do you want to expand?\n");
242 scanf("%d",&m);
243 expand2(ht1,&ht1_head,m,n);
244 break;
245 case 999://!!!格式化!!!
246 printf("formatting...\n");
247 formatting2(&ht1_head,&ht1);
248 break;
249 default://错误码提示
250 printf("Please check your option number!\n");
251 }
252 }
253 }
254
255 else
256 {
257 printf("请检查操作数!\n");
258 printf("Please check your option number!\n");
259 }
260
261 break; //还在循环里面,完成用户功能之后要break跳出去
262 }
263 }//for
264
265 }//if 教师
266
267 //从这里开始学生的操作步骤,因为没有认证,功能也少,相对就简单一些
268 else if(a==2)
269 {
270 printf("请选择菜单语言\n");
271 printf("Chose the menu language.\n");
272 printf("1---------中文\n");
273 printf("2---------English\n");
274 scanf("%d",&op_stu_l);
275 if(op_stu_l==1) //用户选择中文菜单
276 {
277 while(1)
278 {
279 menu_stu1();
280 printf("请输入操作数:\n");
281 scanf("%d",&op_stu);
282 switch(op_stu)
283 {
284 case 0:
285 //格式化
286 formatting1(&ht1_head,&ht1);
287 //顺便关闭一下文件
288 if(file!=-1)
289 {
290 close(file);
291 }
292 printf("已退出!\n");
293 printf("祝您生活愉快!\n");
294 return 0;
295 case 1://学生查找信息,这其实是一个综合性的大步骤,因为项目都是黑匣子,我
不需要用户具体地去做每一步,我直接一步到位,一个按钮即完成查找。
296 printf("请输入想要查找的学生姓名:\n");
297 scanf("%s",stu1.Name);
298 sprintf(sss,"%s.txt",stu1.Name);
299 //打开文件
300 file = open(sss,O_RDWR);
301 if(file==-1)
302 {
303 printf("该学生不存在\n");
304 return -1;
305 }
306 //获取文件中的数据
307 //读到data_type类型的stu1里面去
308 g=read(file,&stu1,sizeof(data_type));
309 if(g==-1)
310 {
311 printf("读取失败\n");
312 return -1;
313 }
314 n=10;
315 infomalloc(&ht1,&ht1_head,n);
316 add1(ht1_head,&ln_new,stu1);
317
318
319
320
321
322
323
324 //现在正常查找即可。
325
326
327 ln0 = search1(ht1_head,stu1.ID);
328 if(ln0 != NULL)
329 {
330 printf("该学生的信息如下:\n");
331 printf("姓名:%s\n",ln0->stu_data.Name);
332 printf("性别:%s\n",ln0->stu_data.Gender);
333 printf("学号:%s\n",ln0->stu_data.ID);
334 printf("成绩:%s\n",ln0->stu_data.Grade);
335 putchar('\n');
336 printf("信息有误?点我反馈老师\n");
337 }
338 break;
339 default:
340 printf("请检查操作数!\n");
341 }
342 }//while
343 }
344 else if(op_stu_l==2) //用户选择英文菜单
345 {
346 while(1)
347 {
348 menu_stu2();
349 printf("Please input the option number!\n");
350 scanf("%d",&op_stu);
351 switch(op_stu)
352 {
353 case 0:
354 formatting2(&ht1_head,&ht1);
355 if(file!=-1)
356 {
357 close(file);
358 }
359 printf("Exited!\n");
360 printf("Have a nice day!\n");
361 return 0;
362 case 1:
363 printf("Please input the name of student you want to check:\n");
364 scanf("%s",stu1.Name);
365 sprintf(sss,"%s.txt",stu1.Name);
366 file = open("student.txt",O_RDWR);
367 if(file==-1)
368 {
369 printf("This student doesn't exist!\n");
370 return -1;
371 }
372 g=read(file,&stu1,sizeof(data_type));
373 if(g==-1)
374 {
375 printf("read failed!\n");
376 return -1;
377 }
378 n=10;
379 infomalloc(&ht1,&ht1_head,n);
380 add2(ht1_head,&ln_new,stu1);
381
382
383
384 ln0 = search2(ht1_head,ID);
385 if(ln0 != NULL)
386 {
387 printf("The student's information is as follows:\n");
388 printf("Name:%s\n",ln0->stu_data.Name);
389 printf("Gender:%s\n",ln0->stu_data.Gender);
390 printf("ID:%s\n",ln0->stu_data.ID);
391 printf("Grade:%s\n",ln0->stu_data.Grade);
392 }
393 break;
394 default:
395 printf("Please check your option number!\n");
396 }
397 }
398
399 }//英文菜单的尾括号
400 else
401 {
402 printf("请检查操作数!\n");
403 printf("Please check your number!\n");
404 }
405
406 }//学生的步骤
407
408 else
409 {
410 printf("Please check your number!\n");
411 }
412 return 0;
413 }//主函数
2.菜单函数,交互界面(menu.c)
1 #include "../include/main.h"
2
3 void menu_tch1()
4 {
5 putchar('\n');
6 printf("\t ------------------------------------\n");
7 printf("\t| 欢迎来到某某高校学生信息管理系统 |\n");
8 printf("\t| |\n");
9 printf("\t| 1--------开辟空间 |\n");
10 printf("\t| 2--------添加学生信息 |\n");
11 printf("\t| 3--------修改学生信息 |\n");
12 printf("\t| 4--------查找学生信息 |\n");
13 printf("\t| 5--------删除学生信息 |\n");
14 printf("\t| 6--------增扩空间 |\n");
15 printf("\t| 0--------退出系统 |\n");
16 printf("\t| |\n");
17 printf("\t| 999--------!!!格式化!!! |\n");
18 printf("\t ------------------------------------\n");
19 }
20 void menu_tch2()
21 {
22 putchar('\n');
23 printf("\t --------------------------------------------\n");
24 printf("\t| Welcome to the XXX university's MSSI |\n");
25 printf("\t| |\n");
26 printf("\t| 1--------infomalloc |\n");
27 printf("\t| 2--------Add student |\n");
28 printf("\t| 3--------Modify student's info |\n");
29 printf("\t| 4--------Search student |\n");
30 printf("\t| 5--------Delete student |\n");
31 printf("\t| 6--------Expand space |\n");
32 printf("\t| 0--------Quit |\n");
33 printf("\t| |\n");
34 printf("\t| 999--------!!!formatting!!! |\n");
35 printf("\t --------------------------------------------\n");
36 }
37 void menu_stu1()
38 {
39 putchar('\n');
40 printf("\t ------------------------------------\n");
41 printf("\t| 欢迎来到某某高校学生信息管理系统 |\n");
42 printf("\t| |\n");
43 printf("\t| 1--------查询信息 |\n");
44 printf("\t| 0--------退出 |\n");
45 printf("\t| |\n");
46 printf("\t ------------------------------------\n");
47 }
48 void menu_stu2()
49 {
50 putchar('\n');
51 printf("\t --------------------------------------------\n");
52 printf("\t| Welcome to the XXX university's MSSI |\n");
53 printf("\t| |\n");
54 printf("\t| 1--------Search student's info |\n");
55 printf("\t| 0--------Quit |\n");
56 printf("\t| |\n");
57 printf("\t --------------------------------------------\n");
58 }
3.开辟空间(infomalloc.c)
1 #include "../include/main.h"
2
3 //开辟空间
4 //参数1:指向欲开辟空间首地址的 指针的地址
5 //参数2:哈希表表头指针 的地址
6 //参数3:欲开辟的单元格数量
7 int infomalloc1(link_node *** ht1,ht ** ht1_head,int n)
8 {
9 if(ht1==NULL)
10 {
11 printf("空指针错误!\n");
12 return -1;
13 }
14 if(ht1_head==NULL)
15 {
16 printf("空指针错误!\n");
17 return -1;
18 }
19 if(n==0 || n<0)
20 {
21 printf("请检查你的行数!\n");
22 return -1;
23 }
24 //开辟哈希表的空间
25 *ht1 = (link_node**)malloc(n * sizeof(link_node));
26 if(*ht1==NULL)
27 {
28 printf("申请空间失败!\n");
29 return -1;
30 }
31 printf("申请空间成功!\n");
32 //哈希表的初始化
33 int i = 0;
34 for(;i<n;i++)
35 {
36 (*ht1)[i]=NULL; //指针数组的初始化
37 }
38 // printf("哈希表初始化完成!\n"); //留下面一句提示即可,保证系统的可适性
39
40 //开辟哈希表表头的空间
41 *ht1_head = (ht*)malloc(sizeof(ht));
42 if(*ht1_head==NULL)
43 {
44 printf("申请空间失败!\n");
45 return -1;
46 }
47 printf("申请空间成功!\n");
48 //哈希表表头的初始化
49 (*ht1_head)->pArr = *ht1;
50 (*ht1_head)->count = n; //申请了几个单元格的空间count就为几
51
52 printf("表格初始化完成!\n");
53
54 return 0;
55 }
56
57 int infomalloc2(link_node *** ht1,ht ** ht1_head,int n)
58 {
59 if(ht1==NULL)
60 {
61 printf("NULL Error!\n");
62 return -1;
63 }
64 if(ht1_head==NULL)
65 {
66 printf("NULL Error!\n");
67 return -1;
68 }
69 if(n==0 || n<0)
70 {
71 printf("Please check your row number\n");
72 return -1;
73 }
74 //开辟哈希表的空间
75 *ht1 = (link_node**)malloc(n * sizeof(link_node));
76 if(*ht1==NULL)
77 {
78 printf("malloc failed!\n");
79 return -1;
80 }
81 printf("malloc succeeded!\n");
82 //哈希表的初始化
83 int i = 0;
84 for(;i<n;i++)
85 {
86 (*ht1)[i]=NULL; //指针数组的初始化
87 }
88 printf("The hash table has been initialized!\n");
89
90 //开辟哈希表表头的空间
91 *ht1_head = (ht*)malloc(sizeof(ht));
92 if(*ht1_head==NULL)
93 {
94 printf("malloc failed!\n");
95 return -1;
96 }
97 printf("malloc succeeded!\n");
98 //哈希表表头的初始化
99 (*ht1_head)->pArr = *ht1;
100 (*ht1_head)->count = n; //申请了几个单元格的空间count就为几
101 printf("The head of hash table has been initialized!\n");
102
103 return 0;
104 }
4.添加学生信息(add.c)
1 #include "../include/main.h"
2
3 //添加学生信息
4 //添加到哪里?
5 //参数1:哈希表的地址,传表头和表均可。
6 //添加什么?
7 //参数2:指向一个链表节点的指针 的地址,传地址是因为我要修改它,即link_node ** stu_new
8 //参数3:学生的个人信息,在外面即初始化完毕,是一个结构体,也是链表的数据域
9 int add1(ht * ht1_head,link_node ** ln_new,data_type stu1)
10 {
11 if(ht1_head==NULL)
12 {
13 printf("表格不存在!\n");
14 return -1;
15 }
16 if(ln_new==NULL)
17 {
18 printf("空指针错误!\n");
19 return -1;
20 }
21 //初始化链表节点
22 *ln_new = (link_node*)malloc(sizeof(link_node));
23 if(*ln_new==NULL)
24 {
25 printf("申请空间失败!\n");
26 return -1;
27 }
28 memset(&(*ln_new)->stu_data,0,sizeof(data_type));//数据域写空
29 (*ln_new)->pNext = NULL;//指针域置空
30 (*ln_new)->stu_data = stu1;//在该链表节点的数据域写值
31 //通过哈希函数求得在表中的位置
32 int pos = hash_func(stu1.ID);
33 //重链接
34 (*ln_new)->pNext = ht1_head->pArr[pos];//保护后面的节点
35 ht1_head->pArr[pos] = *ln_new;
36
37 putchar('\n');
38 printf("学生信息已录入!\n");
39 return 0;
40 }
41
42 int add2(ht * ht1_head,link_node ** ln_new,data_type stu1)
43 {
44 if(ht1_head==NULL)
45 {
46 printf("The hash table doesn't exist!\n");
47 return -1;
48 }
49 if(ln_new==NULL)
50 {
51 printf("NULL Error!\n");
52 return -1;
53 }
54 //初始化链表节点
55 *ln_new = (link_node*)malloc(sizeof(link_node));
56 if(*ln_new==NULL)
57 {
58 printf("malloc failed!\n");
59 return -1;
60 }
61 memset(&(*ln_new)->stu_data,0,sizeof(data_type));//数据域写空
62 (*ln_new)->pNext = NULL;//指针域置空
63 (*ln_new)->stu_data = stu1;//在该链表节点的数据域写值
64 //通过哈希函数求得在表中的位置
65 int pos = hash_func(stu1.ID);
66 //重链接
67 (*ln_new)->pNext = ht1_head->pArr[pos];//保护后面的节点
68 ht1_head->pArr[pos] = *ln_new;
69
70 putchar('\n');
71 printf("The information of this student has been written.\n");
72 return 0;
73 }
74
5.修改学生信息(modify.c)
1 #include "../include/main.h"
2
3 //修改学生信息
4 //参数1:哈希表的地址
5 //参数2:学生的个人信息,stu1
6 int modify1(ht * ht1_head,data_type stu1)
7 {
8 link_node * ln_mod = search1(ht1_head,stu1.ID);
9 if(ln_mod==NULL)
10 {
11 printf("修改失败!\n");
12 return -1;
13 }
14 else
15 {
16 ln_mod->stu_data = stu1;
17 printf("修改成功!\n");
18 return 0;
19 }
20 }
21
22 int modify2(ht * ht1_head,data_type stu1)
23 {
24 link_node * ln_mod = search2(ht1_head,stu1.ID);
25 if(ln_mod==NULL)
26 {
27 printf("madification failed!\n");
28 return -1;
29 }
30 else
31 {
32 ln_mod->stu_data = stu1;
33 printf("modification completed!\n");
34 return 0;
35 }
36 }
37
6.查找学生信息(search.c)
1 #include "../include/main.h"
2
3 //查找学生信息
4 //按照我上面的哈希算法以及我的ID取值,
5 //我的哈希表将是一个(n+m)行,不超过2列的表,也就是说没有冲突。
6 //所以检索条件是 单元格内地址不为空即可。
7 //如果不为空,用户可能还想要查看里面节点的数据域,而不是简单看一下有没有就完了。
8 //所以返回值是一个地址。
9 link_node * search1(ht * ht1_head,char * ID)
10 {
11 int pos = hash_func(ID);//根据ID索引到哈希表的具体位置
12 if( ht1_head->pArr[pos] == NULL )
13 {
14 printf("没有该学生!\n");
15 return NULL;
16 }
17 else
18 {
19 printf("检索到该学生!\n");
20
21 return ht1_head->pArr[pos]; //返回该学生在内存空间的地址!
22 }
23
24
25 }
26
27 link_node * search2(ht * ht1_head,char * ID)
28 {
29 int pos = hash_func(ID);//根据ID索引到哈希表的具体位置
30 if( ht1_head->pArr[pos] == NULL )
31 {
32 printf("No such student!\n");
33 return NULL;
34 }
35 else
36 {
37 printf("There is such a student!\n");
38 return ht1_head->pArr[pos]; //返回该学生在内存空间的地址!
39 }
40 }
7.删除学生信息(delete.c)
1 #include "../include/main.h"
2
3 //输入学生ID实现删除
4 //参数1:查找的范围,也就是哈希表的地址
5 //参数2:学生的ID
6 int delete1(ht ** ht1_head,char * ID)
7 {
8 int pos = hash_func(ID);//获取在哈希表的哪一行
9
10 //发现通过调用search2就能实现返回一个想找寻学生节点地址,那么调用它
11 link_node * ln_del = search1(*ht1_head,ID);
12
13 //此处可以选择清空该链表节点,也可以选择不清空,因为按照良好的编程习惯,下次启用该片空间时,肯定会手动清空的。
14 memset(&(ln_del->stu_data),0,sizeof(data_type));
15
16 (*ht1_head)->pArr[pos] = ln_del->pNext; //保护后面的节点
17
18 free(ln_del);//通过ln_del来释放这片空间
19 ln_del = NULL;
20 printf("已删除该学生信息!\n");
21 return 0;
22 }
23
24 int delete2(ht ** ht1_head,char * ID)
25 {
26 int pos = hash_func(ID);//获取在哈希表的哪一行
27
28 //发现通过调用search2就能实现返回一个想找寻学生节点地址,那么调用它
29 link_node * ln_del = search2(*ht1_head,ID);
30
31 //此处可以选择清空该链表节点,也可以选择不清空,因为按照良好的编程习惯,下次启用该片空
间时,肯定会手动清空的。
32 memset(&(ln_del->stu_data),0,sizeof(data_type));
33
34 (*ht1_head)->pArr[pos] = ln_del->pNext; //保护后面的节点
35
36 free(ln_del);//通过ln_del来释放这片空间
37 ln_del = NULL;
38 printf("delete completed!\n");
39 return 0;
40 }
8.增扩空间(expand.c)
1 #include "../include/main.h"
2
3 //增扩空间,可以用realloc。
4 //参数1:指向原有哈希表的指针 的地址,即&ht1。
5 //参数2:哈希表表头指针 的地址,即&ht1_head。
6 //参数3:增扩的单元格数
7 //参数4:原来已有的单元格数,用来计算增扩的起始地址,增扩一定是在开辟了之后,那么就用之前的n
8 int expand1(link_node ** ht1,ht ** ht1_head,int m,int n)
9 {
10 if(ht1==NULL) //检查参数1
11 {
12 printf("表格不存在!\n");
13 return -1;
14 }
15 if(ht1_head==NULL) //检查参数2
16 {
17 printf("空指针错误!\n");
18 return -1;
19 }
20 if(n==0) //这一步是为了增强程序的鲁棒性
21 {
22 // printf("Dangerous!!! Prerequisite doesn't exist.\n");
23 return -1;
24 }
25 if(m==0 || m<0) //检查参数3
26 {
27 // printf("Are you serious???\n");
28 printf("请检查你的输入数!\n");
29 return -1;
30 }
31
32 // *ht1 = (*ht1)+n; //将哈希表的指针向后移动n个链表节点
33
34 //现在ht1已指向我想要开辟的位置
35 ht1 = (link_node**)realloc(ht1,(m+n)*sizeof(link_node));//这一步即增扩m个链表节点的空间
36 if(ht1==NULL)
37 {
38 printf("申请空间失败!\n");
39 return -1;
40 }
41 //再修改一下表头的count数据即可
42 (*ht1_head)->count = n+m;
43
44 printf("增扩空间完毕!\n");
45 return 0;
46 }
47
48 int expand2(link_node ** ht1,ht ** ht1_head,int m,int n)
49 {
50 if(ht1==NULL) //检查参数1
51 {
52 printf("The hash table doesn't exist!\n");
53 return -1;
54 }
55 if(ht1_head==NULL) //检查参数2
56 {
57 printf("NULL Error!\n");
58 return -1;
59 }
60 if(n==0) //这一步是为了增强程序的鲁棒性
61 {
62 printf("Dangerous!!! Prerequisite doesn't exist.\n");
63 return -1;
64 }
65 if(m==0 || m<0) //检查参数3
66 {
67 printf("Are you serious???\n");
68 printf("Please check your number\n");
69 return -1;
70 }
71
72 // *ht1 = (*ht1)+n; //将哈希表的指针向后移动n个链表节点
73 //现在ht1已指向我想要开辟的位置
74 ht1 = (link_node**)realloc(ht1,(m+n)*sizeof(link_node));//这一步即增扩m个链表节点的空间
75 if(ht1==NULL)
76 {
77 printf("malloc failed!\n");
78 return -1;
79 }
80 //再修改一下表头的count数据即可
81 (*ht1_head)->count = n+m;
82
83 printf("Expansion completed!\n");
84 return 0;
85 }
9.格式化空间(formatting.c)
1 #include "../include/main.h"
2
3 //!!!格式化!!!
4 //释放并清空哈希表的所占空间
5 int formatting1(ht ** ht1_head,link_node *** ht1)
6 {
7 if(*ht1_head==NULL || *ht1==NULL)
8 {
9 printf("表格不存在!\n");
10 return -1;
11 }
12
13 link_node * ln_des = NULL;//创建一个指向某一链表节点的指针变量,准备头删
14 // ln_des = (*ht1_head)->pArr[0];
15 int i;
16 for(i=0;i<((*ht1_head)->count);i++)
17 {
18 while(ln_des!=NULL)
19 {
20 //先让指针变量指向哈希表第一个单元格的后面第一个链表节点,可以简单理解为哈希表第一行链表的首节点
21 ln_des = (*ht1_head)->pArr[i];
22 //按照惯例,保护后面的节点,但其实我这种哈希算法其实是没有冲突的,这里可以不保护
23 (*ht1_head)->pArr[i] = ln_des->pNext;
24 free(ln_des);
25 }//第i行清理完毕
26
27 //释放第i个单元格的空间
28 free((*ht1_head)->pArr[i]);
29 (*ht1_head)->pArr[i] = NULL;
30 }
31 ln_des = NULL;
32
33 //现在哈希表是一个全部为空指针的指针数组
34 //还需要释放原来 指向哈希表的指针 ht1 以及 哈希表表头指针 ht1_head对应的空间
35 //并把其置空
36 free(*ht1);
37 *ht1 = NULL;
38 free(*ht1_head);
39 *ht1_head = NULL;
40
41 printf("格式化完毕!\n");
42 return 0;
43 }
44
45 int formatting2(ht ** ht1_head,link_node *** ht1)
46 {
47 if(*ht1_head==NULL || *ht1==NULL)
48 {
49 printf("The hash table doesn't exist!\n");
50 return -1;
51 }
52
53 link_node * ln_des = NULL;//创建一个指向某一链表节点的指针变量,准备头删
54 int i;
55 for(i=0;i<(*ht1_head)->count;i++)
56 {
57 while(ln_des!=NULL)
58 {
59 //先让指针变量指向哈希表第一个单元格的后面第一个链表节点,可以简单理解为哈希表第一行链表的首节点
60 ln_des = (*ht1_head)->pArr[i];
61 //按照惯例,保护后面的节点,但其实我这种哈希算法其实是没有冲突的,这里可以不保护
62 (*ht1_head)->pArr[i] = ln_des->pNext;
63 free(ln_des);
64 ln_des = NULL;
65 }//第i行清理完毕
66
67 //释放第i个单元格的空间
68 free((*ht1_head)->pArr[i]);
69 (*ht1_head)->pArr[i] = NULL;
70 }
71
72 //现在哈希表是一个全部为空指针的指针数组
73 //还需要释放原来 指向哈希表的指针 ht1 以及 哈希表表头指针 ht1_head对应的空间
74 //并把其置空
75 free(*ht1);
76 *ht1 = NULL;
77 free(*ht1_head);
78 *ht1_head = NULL;
79
80 printf("formatting completed!\n");
81 return 0;
82 }
83
10.哈希函数(hash_func.c)
1 #include "../include/main.h"
2
3 //哈希算法根据数据而定.
4 //我的数据是学生的学号,我打算给一组 连续的100,101,102...这样的数字
5 //那么我对100取余数就能得到一个地址。
6 //
7 //值得一提的是,按照个人ID号码去取哈希地址的话,因为ID数据高度相似 取值连续 且 绝不重复,
8 //所以在对ID进行索引的前提下,只要哈希算法足够科学,完全能做到哈希表索引不冲突。
9 int hash_func(char * ID)
10 {
11 int i = atoi(ID);//就是一个字符型数字到整形数字的转化,可以man一下
12 return (i%100);
13 }
14
三、待优化点:
1.
在修改学生信息的时候,可以减少用户的操作数,比如,可以减少录入修改信息的条数,只录入欲修改的信息。
2.
格式化按钮可以增加二次确认。
3.
另外,我所做的双语版本其实就是把(所有函数和选择)里面的提示语都做了一个第二语言版本,
如果我习惯不在子函数里写提示语,而是在主函数调用时根据执行的情况(子函数的返回值)去写提示语,或许可以不必写两遍子函数,代码量可以减半。
但这并不是我的编程习惯,不做优化。