前言
师弟: “经过几轮优化之后,我的学生成绩管理系统,感觉已经非常不错了,是我学习以来做的最好的系统了。没想到,还是被嘲笑了。”
我:“怎么被嘲笑了?”
师弟:“程夏她说: 你在录入学生的时候,id是增序录入的,在查询的时候,就不能高效一点查询,不去遍历整个数据?”
我:“确定这个女生不是我们计算机系的?”
师弟:“的确不是我们计算机系的呢。”
我:“那人家学习的速度和你相比,像是龟兔赛跑呀。”
看师弟有点难受,我:“干嘛这么惆怅,谁笑的开心还不一定呢。在讲二分查找之前,讲个故事吧。”
龟兔赛跑
乌龟小龟情不自禁的喜欢上了兔子小兔,然后就展开自己快速的步伐,去追小兔,可是小兔的速度太快了,小龟怎么也追不上,小龟爬啊爬,爬啊爬,历经了千山万水,日升日落,春去秋来,小兔的影子都没有看到。
这一天黄昏时分,小龟累了,停留了一下脚步。这个时候,金黄的阳光照射过来,绚丽而灿烂,小龟沉醉在其中,忘记了心中所想,感觉身上满满的都是幸福,闭上了眼睛,尽情的享受着这份快乐。
“你放弃吧。”小龟被一声话语惊醒,本来很生气的小龟,瞬间变得不生气了,替换的更多的是内心的喜悦。因为说话的是小兔,自己满心喜欢和期待的小兔啊。
小龟倔强的回道:“不,我绝不放弃。”但是坚定的说完了以后,小龟内心产生了一个疑问。“真的是决不放弃吗?我能够追的上吗?”疑问很快就被小龟否定了。
“那好吧,你那么笨,既然想追,你就追吧,只要你能够追上我的步伐,那我就可以考虑和你在一起。”说完以后,还没等小龟反应,就已经绝尘而去。
看着小兔远去的背影,夹杂着激起的灰尘,小龟喜中也参含着忧。高兴的是自己有机会,不开心的是自己似乎又没有机会。
小龟重新整理了一下背上的行囊,上路了。目标很明确:追上小兔。
这一年在风吹雨打中过去了。
小龟犹豫了。“我真的能够追上小兔吗?就我这种速度,就我这么笨拙。或许我根本就不适合。或许我该重新认识一下现实,接受现实。”
就在小龟自我否定的时候,不知不觉来到了一个寺庙的门口。门口坐着两个和尚。一个和尚胖胖的,满脸的赘肉,看似很富裕的样子。另一个和尚,有点沧桑,略显消瘦,但是精神饱满。胖和尚惊讶的听着瘦和尚讲述着他去南海的经历。
原来一年前,瘦和尚说道:自己想去南海看看。胖和尚就笑话他,说自己多年前就开始攒钱,常常想着买船,顺江而下,去南海游历一番,可是没有实现,你这么穷,凭什么啊。没想到的是,这个瘦和尚竟然从南海游历回来了。胖和尚没有成功,瘦和尚竟然成功了。
小龟看着瘦和尚的面庞,不知道为什么感觉大受鼓舞,向他拜了拜。“天下事有难易乎?为之则难者亦易矣,不为则易者亦难矣。”小龟轻快的唱着歌就又重新出发了,扫去了之前的不快。
又是一年,伴随着风雨度过。
看着北归的大雁,小龟不知不觉中牵动了归家的情思,眼泪不自觉的流落了下来。
“枯藤老树昏鸦,小桥流水人家,古道西风瘦马,夕阳西下,断肠人在天涯。”一阵悲怆的诗歌从远处被风吹了过来。小龟沿着声音传来的方向看过去,只见一个身形消瘦的长衫游客,牵着一匹瘦瘦的马。不知道为什么小龟内心中很是凄凉。竟然不自觉的在这里放声大哭起来,很是想念在堂的老龟父母。
父母在,不远游。
“归去来兮!”小龟擦干了眼泪,看着夕阳西下,转过了身,朝家的方向爬去。
归家的路好长啊!小龟没有想到这些年竟然走了这么多的路。
终于,到了一条水边,一条熟悉的水边,小的时候曾经来过的地方。站在水边的高处,可以遥遥望见家乡的方向。
不知道为什么,前段时间日夜紧赶,就是想早点回家,这会快要到家了,反而有些羞涩。难道这是“近乡情更怯”。想想自己当年为爱而行,何尝不是在家乡闹得沸沸扬扬。
小龟长舒了一口气,收回了视线,又踏上了回家的路程。
归家途中经过一片农田,在田边不远处有一个老农,手中攥着一个东西,在焦急的等待,眼神紧紧的盯着田边的一棵树桩。
小龟好奇的走过去,问道:“大伯,你这是在等什么吗?”看清了大伯手中的护手后,小龟心头不禁一震。因为这是小龟在几年前送给小兔的生日礼物,这个护手上面有小兔的名字,他一眼就能够认出。为什么小兔的东西会在这儿呢?还没等大伯回答,小龟继续问道:“大伯,你这手中的手环是哪买的啊?好漂亮啊,我也想买一个。”
大伯晃了晃手中的手环,回道:“你说这个啊,不是我买的,是几天前的那个兔子的。”
小龟心头一紧,“前几天的兔子?她怎么了吗?”
大伯笑道:“她跑的太快,一下子撞死在了这棵树桩上了。瞧,血迹还在这儿呢。我在这儿继续等待,看看还有没有兔子过来,那样的话,我也就不用种庄稼了。”
小龟不知道为什么有点眩晕,终于抑制不住伤心,放声大哭了起来。伤心不止,眼泪顺着眼角就流了出来。
大伯看着大哭的乌龟,感觉默名其妙,转身就走了,嘀咕道:“今天,看样子是没有什么收获了,还是回去吧。”
大伯离开以后,小龟哭的更加伤心了,泪眼模糊中似乎看见了小兔的影子,他不顾一切的冲了上去,一把抱住了她,哭喊着说道:“小兔,你为什么,为什么,为什么这么早就离开了。”
“小龟,你这是干什么?”小兔说道,心中说不出的开心。
小龟听到了这话还没有反应过来,擦了擦眼泪。看了看眼前的小兔,不敢相信自己的眼睛。
“你还活着?”小龟兴奋的叫道。
“我当然还活着了,不然你以为呢!”小兔说道。“那滩血迹,是偷我护手的兔子的。走吧,我们回家。回去给你讲这个故事。”
“回家?”小龟疑惑地说道。
“不是说了嘛,只要你追上我,我就和你在一起。你怎么还是这么笨!”小兔说道。
小龟和小兔幸福的回家了。
二分查找
二分查找是一种在有序数组中查找特定元素的算法,其基本思想是将待查找区间分为两部分,每一步比较待查找元素与区间中间元素的大小,从而将搜索范围缩小到一半,又被称为折半查找。
/*** @arr: 有序数组* @l: 待查找区间左端点* @r: 待查找区间右端点* @x: 需要查找的元素*/
int binary_search(int *arr, int l, int r, int x) {while (l <= r) {// 计算中间位置int m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出// 检查x是否存在于中间位置if (arr[m] == x)return m;// 若x大,则忽略左半部分if (arr[m] < x) {l = m + 1;} else {// 若x小,则忽略右半部分r = m - 1;}// 若未找到元素,返回-1return -1;
}
完整代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for access() function#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"
#define TRUE 1
#define FALSE 0typedef struct {int id; // 学号char name[MAX_NAME_LEN]; // 姓名float score; // 成绩
} Student;int student_count = 0; // 学生数量Student *students; // 学生数组指针
int g_max_student = MAX_STUDENTS;Student *stu_sys_init(int num)
{Student *stu_sys;stu_sys = malloc(num * sizeof(Student));if (stu_sys == NULL) {printf("student system malloc failed!\n");}return stu_sys;
}int write_student_info(Student *s)
{FILE *fp = fopen(STUDENT_SYSTEM, "a");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);fclose(fp);return 0;
}int check_if_student_exsit(int id)
{int i;for(i = 0; i < student_count; i++) {if(students[i].id == id) {return 1;}}return 0;
}void update_student_info(Student s, int need_write)
{Student *stu_reinit;int old_max_student;int i;if(student_count >= g_max_student) {old_max_student = g_max_student;g_max_student = g_max_student << 1;stu_reinit = stu_sys_init(g_max_student);if (stu_reinit == NULL) {printf("Database is full!\n");return;}memcpy(stu_reinit, students, old_max_student * sizeof(Student));free(students);students = stu_reinit;}if (!check_if_student_exsit(s.id)) {students[student_count++] = s;if (need_write) {printf("Student added successfully, all student: %d!\n", student_count);write_student_info(&s);}} else {printf("student has in db, do nothing!\n");}
}void add_student()
{Student s;printf("Enter student ID: ");scanf("%d", &s.id);printf("Enter student name: ");scanf("%s", s.name);s.score = 0.0; // 初始成绩设置为0update_student_info(s, TRUE);
}void print_title()
{printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}void display_all_students()
{int i;printf("-------- All students info --------\n");if (student_count == 0) {printf("No students!\n");} else {print_title();for(i = 0; i < student_count; i++) {printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);}}printf("-------- End -----------\n");
}/*** * @arr: 有序数组* * @l: 待查找区间左端点* * @r: 待查找区间右端点* * @x: 需要查找的元素* */
int binary_search(Student *s, int l, int r, int target)
{int m;while (l <= r) {// 计算中间位置m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出// 检查x是否存在于中间位置if (s[m].id == target)return m;// 若x大,则忽略左半部分if (s[m].id < target) {l = m + 1;} else {// 若x小,则忽略右半部分r = m - 1;}}// 若未找到元素,返回-1return -1;
}void find_student_by_id()
{int id, i, ret;printf("Enter student ID to search: ");scanf("%d", &id);ret = binary_search(students, 0, student_count, id);if (ret != -1) {print_title();printf("%-4d %-10s %-.2f\n", students[ret].id, students[ret].name, students[ret].score);return;}printf("Student with ID %d not found!\n", id);
}void find_student_by_name()
{int i, is_find = 0;char name[MAX_NAME_LEN];printf("Enter student name to search: ");scanf("%s", name);for(i = 0; i < student_count; i++) {if(strcmp(students[i].name, name) == 0) {print_title();printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);is_find = 1;}}if (is_find == 0) {printf("Student with name %s not found!\n", name);}
}void add_score()
{int id, i;float score;printf("Enter student ID: ");scanf("%d", &id);printf("Enter student score: ");scanf("%f", &score);for(i = 0; i < student_count; i++) {if(students[i].id == id) {students[i].score = score;printf("Score added successfully!\n");return;}}printf("Student with ID %d not found!\n", id);
}void display_average_score()
{float total = 0.0;int i;for(i = 0; i < student_count; i++) {total += students[i].score;}printf("Average score of all students: %.2f\n", total / student_count);
}int init_student_info()
{if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在return 0;}FILE *fp = fopen(STUDENT_SYSTEM, "r");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}#define BUF_SIZE 1024char buf[BUF_SIZE];int i = 0;Student s;while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {sscanf(buf, "%d %s %f\n", &s.id, s.name, &s.score);update_student_info(s, FALSE);}fclose(fp);return 0;}void swap(Student *a, Student *b)
{Student tmp = *a;*a = *b;*b = tmp;
}void bubble_sort_by_score(Student *s, int n)
{int i, j;for (i = 0; i < n-1; i++) {for (j = 0; j < n-i-1; j++) { // 最后 i 个已经排序好了, 遍历未排序的部分if (s[j].score < s[j+1].score) {// 如果当前元素大于后面的元素,交换它们swap(&s[j], &s[j+1]);}}}
}int main()
{int choice;int ret;students = stu_sys_init(MAX_STUDENTS);if (students == NULL) {printf("student system init failed, exit!\n");return -1;}ret = init_student_info();if (ret) {printf("init_student_info failed!\n");return 1;}display_all_students();do {printf("\nStudent Score Management System\n");printf("0. Exit\n");printf("1. Add Student\n");printf("2. Display All Students\n");printf("3. Find Student by ID\n");printf("4. Find Student by Name\n");printf("5. Add Score\n");printf("6. Display Average Score\n");printf("7. Display by Score sort\n");printf("Enter your choice: ");scanf("%d", &choice);switch(choice) {case 0:printf("Exiting...\n");break;case 1:add_student();break;case 2:display_all_students();break;case 3:find_student_by_id();break;case 4:find_student_by_name();break;case 5:add_score();break;case 6:display_average_score();break;case 7:bubble_sort_by_score(students, student_count);display_all_students();break;default:printf("Invalid choice!\n");}} while(choice != 0);return 0;
}