1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #define N 3
5 #define LEN (Student*) malloc(sizeof(Student))
6 /* 学生数据结构 */
7 typedef struct node
8 {
9 char num[20];
10 char name[15];
11 int score[N];
12 int sum;
13 double ave;
14 struct node *next;
15 } Student;
16
17 /* 头指针 */
18 Student *head = NULL;
19 /* 临时指针 */
20 Student *tmp = NULL;
21 /* 课程名称 */
22 char CLASSNAME[N][30] = {"大物", "高数", "c语言"};
23 /* 命令开关 */
24 int SWITCH[16] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
25 /* 函数声明 */
26 int Menu();
27 Student* Init();
28 int CheckNUM(char*);
29 int CheckName(char*);
30 int CheakScore(int score);
31 int Same_NUM(char*);
32 void InputNodeInfo(Student*);
33 void OutputNodeInfo(Student*);
34 Student* SearchFrontNode(Student*);
35 void DeleteNode(Student*);
36 void InsertBefore();
37 void InputList();
38 Student* SearchID(char*);
39 Student* SearchName(char*);
40 void SearchDeleteNode();
41 void OutList();
42 void SearchPrintNode();
43 void Compute();
44 int CmpID(Student*, Student*, int);
45 int CmpSum(Student*, Student*, int);
46 int CmpScore(Student*, Student*, int);
47 Student* SearchMaxNode(int (*cmp)(Student*, Student*, int), int);
48 Student* Sort(int (*cmp)(Student*, Student*, int), int);
49 void OutputToFile(FILE*, Student*, int);
50 void InsertAfter(Student*);
51 void SaveToFile();
52 void LoadFile();
53 void CopyFile();
54 void InsertToFile();
55 void FreeList(Student* p);
56 void Stat();
57 void Quit();
58
59 /* 主函数 */
60 int main()
61 {
62 int n;
63
64 while (1)
65 {
66 n = Menu();
67 {
68 if (n == 1 || n == 15 || SWITCH[1])
69 {
70 switch (n)
71 {
72 /* 执行初始化 */
73 case 1:
74 head = Init();
75 printf("LOOK...初始化成功\n");
76 break;
77 /* 创建链表 ,输入学生信息*/
78 case 2:
79 InputList();
80 break;
81 /* 查找学号或姓名删除信息 */
82 case 3:
83 SearchDeleteNode();
84 break;
85 /* 输出全部学生信息 */
86 case 4:
87 system("cls");
88 OutList();
89 break;
90 /* 按姓名查找学生信息*/
91 case 5:
92 SearchPrintNode();
93 break;
94 /* 保存到文件 */
95 case 6:
96 SaveToFile();
97 break;
98 /* 从文件中读取学生信息*/
99 case 7:
100 if (SWITCH[6])
101 {
102 head = Init();
103 LoadFile();
104 }
105 else
106 {
107 printf("当前文件未保存\n");
108 }
109 break;
110 /* 计算所有学生的总分和平均分 */
111 case 8:
112 Compute();
113 SWITCH[8] = 1;
114 printf("计算完毕\n");
115 break;
116 /* 插入一个学生信息到链表 */
117 case 9:
118 InsertBefore();
119 SWITCH[6] = 0;
120 SWITCH[8] = 0;
121 break;
122 /* 复制文件 */
123 case 10:
124 CopyFile();
125 break;
126 /* 排序,按总分排序并打印学生信息 */
127 case 11:
128 if (SWITCH[8])
129 {
130 head = Sort(CmpSum, 0);
131 system("cls");
132 OutList();
133 }
134 else
135 {
136 printf("请先计算总分!\n");
137 }
138 break;
139 /* 尾部添加一个学生信息到文件中 */
140 case 12:
141 InsertToFile();
142 SWITCH[6] = 0;
143 printf("尾部添加完毕!\n");
144 break;
145 /* 按学号搜索..学生信息*/
146 case 13:
147 if (SWITCH[8])
148 {
149 head = Sort(CmpID, 0);
150 system("cls");
151 OutList();
152 }
153 else
154 {
155 printf("请先计算总分!\n");
156 }
157 break;
158 /* 分类汇总 */
159 case 14:
160 system("cls");
161 Stat();
162 break;
163 /* 结束 */
164 case 15:
165 Quit();
166 break;
167 default:
168 printf("无效命令!\n");
169 fflush(stdin);
170 }
171 system("pause");
172 }
173 else
174 {
175 printf("你必须首先初始化!\n");
176 system("pause");
177 }
178 }
179 }
180
181 system("pause");
182 return 0;
183 }
184
185 /* 菜单 */
186 int Menu()
187 {
188 int n;
189 system("cls");
190 fflush(stdin);
191 printf("*********************************************************************\n");
192 printf("*********************************************************************\n");
193 printf("【01】 初始化........\n");
194 printf("【02】 输入学生信息\n");
195 printf("【03】 查找学号或姓名删除信息\n");
196 printf("【04】 输出全部学生信息\n");
197 printf("【05】 按姓名查找学生信息\n");
198 printf("【06】 保存到文件\n");
199 printf("【07】 从文件中读取学生信息\n");
200 printf("【08】 计算所有学生的总分和平均分\n");
201 printf("【09】 插入一个学生信息到链表中\n");
202 printf("【10】 复制文件\n");
203 printf("【11】 按总分排序并打印学生信息\n");
204 printf("【12】 尾部添加一个学生信息到文件中\n");
205 printf("【13】 按学号搜索..学生信息\n");
206 printf("【14】 分类汇总\n");
207 printf("【15】 退出\n");
208 printf("********************************************************************\n");
209 printf("请输入命令编号: ");
210 scanf("%d", &n);
211 return n;
212 }
213
214 /* 初始化 */
215 Student* Init()
216 {
217 int i;
218 Student *head;
219 head = LEN;
220 head->next = NULL;
221
222 /* 命令开关初始化 */
223 for (i = 1; i < 16; i++)
224 {
225 SWITCH[i] = 0;
226 }
227
228 SWITCH[1] = 1;
229 SWITCH[6] = 1;
230 return head;
231 }
232
233 /* 检查学号 */
234 int CheckNUM(char* s)
235 {
236 int i;
237
238 if (strlen(s) == 0 || strlen(s) > 10) return 0;
239
240 for (i = 0; i < strlen(s); i++)
241 {
242 if (s[i] < '0' || s[i] > '9') return 0;
243 }
244
245 return 1;
246 }
247
248 /* 检查姓名 */
249 int CheckName(char* s)
250 {
251 int i;
252
253 if (strlen(s) == 0 || strlen(s) > 15) return 0;
254
255 for (i = 0; i < strlen(s); i++)
256 {
257 if (!(s[i] >= 'a' && s[i] <= 'z' || s[i] >= 'A' && s[i] <= 'Z')) return 0;
258 }
259
260 return 1;
261 }
262
263 /* 检查分数 */
264 int CheakScore(int score)
265 {
266 if (score > 100 || score <= 0) return 0;
267 return 1;
268 }
269
270 /* 检查相同学号 */
271 int Same_NUM(char* s)
272 {
273 Student *p = head->next;
274 while(p != NULL)
275 {
276 if (strcmp(s, p->num) == 0) return 1;
277 p = p->next;
278 }
279 return 0;
280 }
281
282 /* 给p指向的节点输入信息 */
283 void InputNodeInfo(Student* p)
284 {
285 fflush(stdin);
286
287 /* 学号 */
288 printf("\n请输入学号: ");
289 do
290 {
291 gets(p->num);
292
293 if (!CheckNUM(p->num))
294 {
295 printf("数据不标准,请重新输入学号: ");
296 }
297 else if (Same_NUM(p->num))
298 {
299 printf("检测到此学号存在,请重新输入: ");
300 }
301 }while (!(CheckNUM(p->num) && !Same_NUM(p->num)));
302
303 /* 姓名 */
304 printf("请输入姓名: ");
305 do
306 {
307 gets(p->name);
308 if (!CheckName(p->name))
309 {
310 printf("数据不标准,请重新输入姓名: ");
311 }
312 }
313 while (!CheckName(p->name));
314
315 /* 成绩 */
316 int i;
317 for (i = 0; i < N; i++)
318 {
319 printf("请输入 %s 成绩: ", CLASSNAME[i]);
320 do
321 {
322 fflush(stdin);
323 scanf("%d", &p->score[i]);
324
325 if (!CheakScore(p->score[i]))
326 {
327 printf("数据不标准,请重新输入 %s 成绩: ", CLASSNAME[i]);
328 }
329 }
330 while (!CheakScore(p->score[i]));
331 }
332
333 /* 总分及平均分 */
334 p->sum = -1;
335 p->ave = -1;
336 }
337
338 /* 输出p指向节点的信息 */
339 void OutputNodeInfo(Student* p)
340 {
341 int i;
342 printf("\n");
343 printf("姓名: %s\n", p->name);
344 printf("学号: %s\n", p->num);
345
346 for (i = 0; i < N; i++)
347 {
348 printf("%s 成绩: %d\n", CLASSNAME[i], p->score[i]);
349 }
350
351 /* 计算过才输出 */
352 if (SWITCH[8]) printf("总分: %d\n", p->sum);
353 if (SWITCH[8]) printf("平均分: %.2lf\n", p->ave);
354 }
355
356 /* 返回r的前一个节点 */
357 Student* SearchFrontNode(Student* r)
358 {
359 Student *p = head;
360 while (p->next != r) p = p->next;
361 return p;
362 }
363
364 /* 删除r指向的节点 */
365 void DeleteNode(Student* r)
366 {
367 Student *p = SearchFrontNode(r);
368 p->next = r->next;
369 }
370
371 /* 头插法插入节点 */
372 void InsertBefore()
373 {
374 Student *s = LEN;
375 InputNodeInfo(s);
376 s->next = head->next;
377 head->next = s;
378 }
379
380 /* 输入链表 */
381 void InputList()
382 {
383 int n;
384 printf("有多少个学生信息要输入? ");
385 scanf("%d", &n);
386
387 while (n--)
388 {
389 InsertBefore();
390 }
391 }
392
393 /* 按学号查找 */
394 Student* SearchID(char* num)
395 {
396 Student *p = head->next;
397
398 while (p != NULL)
399 {
400 if (strcmp(p->num, num) == 0) break;
401 p = p->next;
402 }
403
404 return p;
405 }
406
407 /* 按姓名查找 */
408 Student* SearchName(char* name)
409 {
410 Student *p = head->next;
411
412 while (p != NULL)
413 {
414 if (strcmp(p->name, name) == 0) break;
415 p = p->next;
416 }
417
418 return p;
419 }
420
421 /* 按学号或姓名查找删除节点 */
422 void SearchDeleteNode()
423 {
424 Student *p;
425 fflush(stdin);
426 char str[20];
427 char sure[20];
428
429 /* 输入合法性判断 */
430 printf("请输入你要删除的学生的 姓名 或 学号: ");
431 do
432 {
433 gets(str);
434
435 if (!(CheckNUM(str) || CheckName(str)))
436 {
437 printf("数据不标准,请重新输入姓名或学号: ");
438 }
439 }
440 while (!(CheckNUM(str) || CheckName(str)));
441
442 /* 判断是姓名还是学号 */
443 if (str[0] >= '0' && str[0] <= '9')
444 {
445 p = SearchID(str);
446
447 if (p == NULL)
448 {
449 printf("对不起,找不到这个学号\n");
450 }
451 else
452 {
453 OutputNodeInfo(p);
454 printf("确认删除? (输入\"y\"确认,任意键取消): ");
455 if (strcmp(gets(sure), "y") == 0)
456 {
457 DeleteNode(p);
458 printf("删除成功\n");
459 SWITCH[6] = 0;
460 }
461 fflush(stdin);
462 }
463 }
464 else
465 {
466 p = SearchName(str);
467
468 if (p == NULL)
469 {
470 printf("对不起,找不到这个姓名\n");
471 }
472 else
473 {
474 OutputNodeInfo(p);
475 printf("确认删除? (输入\"y\"确认,任意键取消): ");
476 if (strcmp(gets(sure), "y") == 0)
477 {
478 DeleteNode(p);
479 printf("删除成功!\n");
480 SWITCH[6] = 0;
481 }
482 fflush(stdin);
483 }
484 }
485 }
486
487 /* 输出链表 */
488 void OutList()
489 {
490 Student *p = head->next;
491
492 /* 空表处理 */
493 if (p == NULL)
494 {
495 printf("暂无学生信息!\n");
496 }
497
498 while (p != NULL)
499 {
500 OutputNodeInfo(p);
501 p = p->next;
502 }
503 }
504
505 /* 按姓名查找记录并打印 */
506 void SearchPrintNode()
507 {
508 Student *p = head->next;
509 int ok = 1;
510 char name[20];
511 fflush(stdin);
512
513 /* 姓名合法性判断 */
514 printf("请输入你要查找的学生姓名: ");
515 do
516 {
517 gets(name);
518
519 if (!CheckName(name))
520 {
521 printf("数据不标准,请重新输入姓名: ");
522 }
523 }
524 while (!CheckName(name));
525
526 /* 按姓名查找节点 */
527 while (p != NULL)
528 {
529 if (strcmp(p->name, name) == 0)
530 {
531 ok = 0;
532 OutputNodeInfo(p);
533 }
534 p = p->next;
535 }
536
537 if (ok)
538 {
539 printf("对不起,找不到这个姓名\n");
540 }
541 }
542
543 /* 计算总分和均分 */
544 void Compute()
545 {
546 int i;
547 Student *p = head->next;
548
549 while (p != NULL)
550 {
551 int sum = 0;
552
553 for (i = 0; i < N; i++)
554 {
555 sum += p->score[i];
556 }
557
558 p->sum = sum;
559 p->ave = sum * 1.0 /N;
560 p = p->next;
561 }
562 }
563
564 /* 比较学号 */
565 int CmpID(Student* a, Student* b, int k)
566 {
567 return strcmp(a->num, b->num);
568 }
569
570 /* 比较总分 */
571 int CmpSum(Student* a, Student* b, int k)
572 {
573 return b->sum - a->sum;
574 }
575
576 /* 比较各科分数 */
577 int CmpScore(Student* a, Student* b, int k)
578 {
579 return b->score[k] - a->score[k];
580 }
581
582 /* 选择最大元素 */
583 Student* SearchMaxNode(int (*cmp)(Student* a, Student* b, int k), int k)
584 {
585 Student *p = head->next;
586 Student *max = p;
587
588 while (p != NULL)
589 {
590 if (cmp(p, max, k) < 0)
591 {
592 max = p;
593 }
594 p = p->next;
595 }
596
597 return max;
598 }
599
600 /* 排序 */
601 Student* Sort(int (*cmp)(Student* a, Student* b, int k), int k)
602 {
603 Student *newhead = LEN;
604 Student *p = newhead;
605 Student *max;
606
607 while (head->next != NULL)
608 {
609 max = SearchMaxNode(cmp, k);
610 p->next = max;
611 DeleteNode(max);
612 p = p->next;
613 }
614
615 /* 表尾处理 */
616 p->next = NULL;
617 return newhead;
618 }
619
620
621 /* 将s插入链表尾部 */
622 void InsertAfter(Student* s)
623
624 {
625 Student *p = head;
626
627 while (p->next != NULL) p = p->next;
628
629 s->next = NULL;
630 p->next = s;
631 }
632
633 /* 保存到文件 */
634 void SaveToFile()
635 {
636 /* 处理尾部添加表尾情况 */
637 if (SWITCH[12])
638 {
639 InsertAfter(tmp);
640 }
641
642 FILE *fp;
643 int i;
644 Student *p;
645 char file[20];
646 fflush(stdin);
647 printf("请输入要保存的文件名: ");
648 gets(file);
649
650 if ((fp = fopen(file, "wt")) == NULL)
651 {
652 printf("写文件错误.......!\n");
653 return;
654 }
655 for(p = head->next;p!=NULL;p=p->next)
656 fprintf(fp,"%s %s \n",p->name,p->num);
657 for(i=0;i<2;i++)
658 {
659 fprintf(fp,"%d\n",p->score[i]);
660 }
661 printf("文件保存成功!\n");
662 fclose(fp);
663 SWITCH[6] = 1;
664
665 /* 处理尾部添加情况 */
666 if (SWITCH[12])
667 {
668 DeleteNode(tmp);
669 SWITCH[12] = 0;
670 }
671 }
672
673 /* 从文件中读入记录 */
674 void LoadFile()
675 {
676 int i;
677 FILE *fp;
678 char file[20];
679 fflush(stdin);
680 printf("请输入文件名: ");
681 gets(file);
682
683 if ((fp = fopen(file, "rt")) == NULL)
684 {
685 printf("对不起,无法打开文件!\n");
686 return;
687 }
688
689 /* 文件未结束时读入数据 */
690 while (!feof(fp))
691 {
692 Student *s = LEN;
693 fscanf(fp, "%s", s->name);
694 fscanf(fp, "%s", s->num);
695
696 for (i = 0; i < N; i++)
697 {
698 fscanf(fp, "%d", &s->score[i]);
699 }
700
701 s->next = head->next;
702 head->next = s;
703 }
704
705 printf("文件读取成功!\n");
706 fclose(fp);
707 }
708
709 /* 复制文件 */
710 void CopyFile()
711 {
712 FILE *fp1, *fp2;
713 char ch, file1[20], file2[20];
714 fflush(stdin);
715 /* 读入源文件 */
716 printf("请输入源文件名: ");
717 gets(file1);
718
719 if ((fp1 = fopen(file1, "rb")) == NULL)
720 {
721 printf("对不起,无法打开文件!\n");
722 return;
723 }
724
725 /* 读入目标文件 */
726 printf("请输入目标文件名: ");
727 gets(file2);
728
729 if ((strcmp(file1, file2) == 0) || ((fp2 = fopen(file2, "wb")) == NULL))
730 {
731 printf("对不起,无法创建文件!\n");
732 return;
733 }
734
735 /* 逐个字符拷贝 */
736 while (!feof(fp1))
737 {
738 ch = fgetc(fp1);
739
740 if (ch != EOF)
741 fputc(ch, fp2);
742 }
743
744 fclose(fp1);
745 fclose(fp2);
746 printf("文件拷贝成功!\n");
747 }
748
749 /* 尾部添加记录到文件中 */
750 void InsertToFile()
751 {
752 tmp = LEN;
753 InputNodeInfo(tmp);
754 SWITCH[12] = 1;
755 }
756
757 /* 分类统计 */
758 void Stat()
759 {
760 int i, j, n = 0;
761 int sum[N] = {0};
762 Student *p = head->next;
763
764 if (p == NULL)
765 {
766 printf("暂无学生信息,无法统计\n");
767 return;
768 }
769
770 /* 统计各科总分 */
771 while (p != NULL)
772 {
773 /* 记录学生总数 */
774 n++;
775
776 for (i = 0; i < N; i++)
777 {
778 sum[i] += p->score[i];
779 }
780
781 p = p->next;
782 }
783
784 /* 各科分别输出 */
785 for (i = 0; i < N; i++)
786 {
787 printf("%s 总均分: %.2lf\n", CLASSNAME[i], sum[i] * 1.0 / n);
788 head = Sort(CmpScore, i);
789 j = 0;
790 p = head->next;
791
792 while (p != NULL)
793 {
794 j++;
795 printf("第%d名 %s %d\n", j, p->name, p->score[i]);
796 p = p->next;
797 }
798
799 printf("\n");
800 }
801 }
802
803 /* 释放链表 */
804 void FreeList(Student* p)
805 {
806 if (p->next != NULL)
807 {
808 FreeList(p->next);
809 }
810 free(p);
811 }
812
813 /* 退出 */
814 void Quit()
815 {
816 if (!SWITCH[6])
817 {
818 printf("请先保存文件!\n");
819 return;
820 }
821 if (head != NULL)
822 {
823 FreeList(head);
824 }
825 exit(0);
826 }